diff --git a/.github/workflows/spec-check.yml b/.github/workflows/spec-check.yml new file mode 100644 index 0000000..c0a50fa --- /dev/null +++ b/.github/workflows/spec-check.yml @@ -0,0 +1,50 @@ +name: Admin API Spec Check +permissions: + contents: read + +on: + push: + branches: [ main ] + paths: + - 'src/amp/admin/**' + - 'specs/**' + - 'scripts/fetch_spec.py' + - 'scripts/generate_models.py' + - '.github/workflows/spec-check.yml' + pull_request: + branches: [ main ] + paths: + - 'src/amp/admin/**' + - 'specs/**' + - 'scripts/fetch_spec.py' + - 'scripts/generate_models.py' + - '.github/workflows/spec-check.yml' + schedule: + - cron: '0 9 * * 1' # Monday 9am UTC + +jobs: + spec-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v6 + + - name: Set up Python + run: uv python install 3.12 + + - name: Install dependencies + run: uv sync --group dev + + - name: Check spec matches upstream + run: uv run python scripts/fetch_spec.py --check + + - name: Verify models are up to date + run: | + uv run python scripts/generate_models.py + uv run ruff format src/amp/admin/models.py + git diff --exit-code src/amp/admin/models.py || { + echo "::error::Generated models are out of date. Run 'make update-models' and commit the changes." + exit 1 + } diff --git a/.gitignore b/.gitignore index ba8d0fb..50d8c35 100644 --- a/.gitignore +++ b/.gitignore @@ -51,7 +51,6 @@ htmlcov/ # UV/pip cache .uv/ -uv.lock # Data directories (local development) # Large datasets should be downloaded on-demand or mounted via ConfigMaps diff --git a/Makefile b/Makefile index cb5c030..56bb67e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ SHELL := /bin/bash -.PHONY: test test-unit test-integration test-all clean setup lint format generate-models +.PHONY: test test-unit test-integration test-all clean setup lint format generate-models fetch-spec update-models check-spec # Use UV for all commands PYTHON = uv run --env-file .test.env @@ -71,10 +71,22 @@ format: @echo "✨ Formatting code..." $(PYTHON) ruff format . -# Generate Pydantic models from OpenAPI spec +# Spec and model generation +fetch-spec: + @echo "📥 Fetching latest Amp Admin API OpenAPI spec..." + $(PYTHON) python scripts/fetch_spec.py + generate-models: @echo "🏗️ Generating Pydantic models from OpenAPI spec..." $(PYTHON) python scripts/generate_models.py + @echo "🎨 Formatting generated models..." + $(PYTHON) ruff format src/amp/admin/models.py + +update-models: fetch-spec generate-models + +check-spec: + @echo "🔍 Checking Amp Admin API spec for drift..." + $(PYTHON) python scripts/fetch_spec.py --check # Setup development environment setup: @@ -138,6 +150,9 @@ help: @echo " make test-clickhouse - Run ClickHouse tests" @echo " make test-snowflake - Run Snowflake tests" @echo " make test-performance - Run performance tests" + @echo " make fetch-spec - Fetch latest OpenAPI spec" + @echo " make update-models - Fetch spec + regenerate models" + @echo " make check-spec - Check spec for upstream drift" @echo " make lint - Lint code with ruff" @echo " make format - Format code with ruff" @echo " make test-setup - Start test databases" diff --git a/docs/admin_client_guide.md b/docs/admin_client_guide.md index 42e35e2..95ffe86 100644 --- a/docs/admin_client_guide.md +++ b/docs/admin_client_guide.md @@ -13,6 +13,7 @@ The Amp Admin Client provides Python bindings for the Amp Admin API, enabling yo - [Schema Validation](#schema-validation) - [Manifest Generation](#manifest-generation) - [Deployment Workflows](#deployment-workflows) +- [Revision Management](#revision-management) - [Error Handling](#error-handling) ## Installation @@ -38,9 +39,9 @@ from amp import Client # Initialize client with both query and admin capabilities client = Client( - query_url="grpc://localhost:8815", # Flight SQL endpoint + query_url="grpc://localhost:1602", # Flight SQL endpoint admin_url="http://localhost:8080", # Admin API endpoint - auth_token="your-auth-token" # Optional authentication + auth=True # Load auth from ~/.amp/cache ) ``` @@ -79,7 +80,7 @@ client.datasets.register( deploy_response = client.datasets.deploy( namespace='_', name='my_dataset', - version='1.0.0', + revision='1.0.0', parallelism=4, end_block='latest' ) @@ -87,8 +88,8 @@ deploy_response = client.datasets.deploy( # Wait for completion job = client.jobs.wait_for_completion( deploy_response.job_id, - poll_interval=5.0, - timeout=3600.0 + poll_interval=5, + timeout=3600 ) print(f"Job completed with status: {job.status}") @@ -113,15 +114,28 @@ Datasets are versioned using semantic versioning (e.g., `1.0.0`). Each version h - Immutable registration - Independent deployment history +Special tags provide convenient references: +- **latest**: Points to the highest semantic version +- **dev**: Points to a development manifest hash + ### Jobs Jobs represent long-running operations like dataset deployments. Jobs have states: -- **Pending**: Queued for execution +- **Scheduled**: Queued for execution - **Running**: Currently executing - **Completed**: Successfully finished - **Failed**: Encountered an error -- **Cancelled**: Stopped by user +- **Stopped**: Stopped by user + +### Revisions + +Revisions represent physical table storage locations. Each table in a dataset can have multiple revisions, with one active at a time. Revisions track: + +- Storage path (e.g., S3 location) +- Active/inactive status +- Writer job association +- File metadata (Parquet files with block ranges) ## Client Configuration @@ -132,11 +146,11 @@ The `Client` class provides both query and admin functionality: ```python from amp import Client -# Full configuration +# Full configuration with auth file client = Client( - query_url="grpc://localhost:8815", + query_url="grpc://localhost:1602", admin_url="http://localhost:8080", - auth_token="your-token" + auth=True ) # Query operations (Flight SQL) @@ -155,43 +169,45 @@ from amp.admin import AdminClient admin = AdminClient( base_url="http://localhost:8080", - auth_token="your-token" + auth=True ) # Access admin operations admin.datasets.list_all() admin.jobs.get(123) +admin.revisions.list(active=True) ``` -### Backward Compatibility +### Authentication -The legacy `url` parameter still works for Flight SQL: +The client supports three authentication methods (highest to lowest priority): + +1. **Explicit token**: Pass `auth_token="your-token"` directly +2. **Environment variable**: Set `AMP_AUTH_TOKEN` in your environment +3. **Auth file**: Pass `auth=True` to load from `~/.amp/cache/amp_cli_auth` (auto-refreshing, shared with TS CLI) ```python -# This still works -client = Client(url="grpc://localhost:8815") -client.sql("SELECT * FROM eth.blocks") +# Option 1: Explicit token +client = Client(query_url="...", admin_url="...", auth_token="your-token") + +# Option 2: Environment variable +# export AMP_AUTH_TOKEN="eyJhbGci..." +client = Client(query_url="...", admin_url="...") + +# Option 3: Auth file (recommended) +client = Client(query_url="...", admin_url="...", auth=True) ``` -### Environment Variables +> **Note:** You cannot combine `auth=True` with `auth_token` - choose one method. -You can configure the client using environment variables: +### Backward Compatibility -```bash -export AMP_QUERY_URL="grpc://localhost:8815" -export AMP_ADMIN_URL="http://localhost:8080" -export AMP_AUTH_TOKEN="your-token" -``` +The legacy `url` parameter still works for Flight SQL: ```python -import os -from amp import Client - -client = Client( - query_url=os.getenv('AMP_QUERY_URL'), - admin_url=os.getenv('AMP_ADMIN_URL'), - auth_token=os.getenv('AMP_AUTH_TOKEN') -) +# This still works +client = Client(url="grpc://localhost:1602") +client.sql("SELECT * FROM eth.blocks") ``` ## Dataset Operations @@ -206,13 +222,6 @@ client.datasets.register( version='1.0.0', manifest=manifest ) - -# Registration without explicit version (server assigns) -client.datasets.register( - namespace='_', - name='eth_blocks', - manifest=manifest -) ``` ### Listing Datasets @@ -226,6 +235,28 @@ for dataset in response.datasets: print(f" Available versions: {dataset.versions}") ``` +### Inspecting Dataset Schemas + +```python +# Pretty-print dataset structure +client.datasets.inspect('_', 'eth_firehose') +# Output: +# Dataset: _/eth_firehose@latest +# Kind: evm-rpc +# +# blocks (21 columns) +# block_num UInt64 NOT NULL +# timestamp Timestamp NOT NULL +# hash FixedSizeBinary(32) NOT NULL +# ... + +# Get structured schema data programmatically +schema = client.datasets.describe('_', 'eth_firehose') +for table_name, columns in schema.items(): + for col in columns: + print(f"{col['name']}: {col['type']} ({'NULL' if col['nullable'] else 'NOT NULL'})") +``` + ### Getting Dataset Versions ```python @@ -243,9 +274,11 @@ for version_info in versions_response.versions: ```python # Get specific version info -version = client.datasets.get_version('_', 'eth_blocks', '1.0.0') -print(f"Manifest hash: {version.manifest_hash}") -print(f"Created: {version.created_at}") +info = client.datasets.get_version('_', 'eth_blocks', '1.0.0') +print(f"Kind: {info.kind}") +print(f"Manifest hash: {info.manifest_hash}") +print(f"Tables: {info.tables}") +print(f"Start block: {info.start_block}") ``` ### Getting Manifests @@ -261,23 +294,64 @@ print(f"Dependencies: {manifest['dependencies']}") ### Deploying Datasets ```python -# Deploy with options +# Deploy with all options deploy_response = client.datasets.deploy( namespace='_', name='eth_blocks', - version='1.0.0', - parallelism=8, # Number of parallel workers - end_block='latest' # Stop at latest block (vs continuous) + revision='1.0.0', + parallelism=8, # Number of parallel workers (raw datasets only) + end_block='latest', # Stop at latest block (vs continuous) + verify=True, # Cryptographic verification (EVM only) + worker_id='worker-eth-*', # Worker selector (exact ID or glob) + retry_strategy={ # Retry behavior + 'strategy': 'bounded', + 'max_attempts': 3 + } ) print(f"Started job: {deploy_response.job_id}") ``` +#### End Block Options + +The `end_block` parameter controls when processing stops: + +- `None` (default): Continuous mode - never stops, processes new blocks as they arrive +- `"latest"`: Stop at the latest block when the job starts +- `"1000000"`: Stop at absolute block number 1,000,000 +- `"-100"`: Stop at 100 blocks before the latest block + +### Listing Jobs for a Dataset + +```python +# Get jobs for a specific dataset version +jobs = client.datasets.list_jobs('_', 'eth_firehose', 'latest') +for job in jobs.jobs: + print(f'{job.id}: {job.status} (node: {job.node_id})') +``` + +### Restoring Dataset Tables + +```python +# Restore all tables for a dataset version +result = client.datasets.restore('_', 'eth_firehose', 'latest') +print(f'Restored {result.total_files} files') + +# Restore a specific table +client.datasets.restore_table('_', 'eth_firehose', 'latest', 'blocks') + +# Restore with specific location +client.datasets.restore_table('_', 'eth_firehose', 'latest', 'blocks', location_id=42) +``` + ### Deleting Datasets ```python # Delete all versions of a dataset client.datasets.delete('_', 'old_dataset') + +# Delete a specific version +client.datasets.delete_version('_', 'my_dataset', '1.0.0') ``` ## Job Management @@ -290,7 +364,8 @@ job = client.jobs.get(123) print(f"Status: {job.status}") print(f"Node: {job.node_id}") -print(f"Descriptor: {job.descriptor}") +print(f"Created: {job.created_at}") +print(f"Updated: {job.updated_at}") ``` ### Listing Jobs @@ -310,6 +385,25 @@ if response.next_cursor: ) ``` +### Creating Jobs + +```python +from amp.admin.models import CreateJobRequest1, CreateJobRequest2, Kind, Kind1 + +# Create a garbage collection job +gc_request = CreateJobRequest1(kind=Kind.gc) +response = client.jobs.create(gc_request) +print(f"GC job: {response.job_id}") + +# Create a raw materialization job with options +raw_request = CreateJobRequest2( + kind=Kind1.materialize_raw, + worker_id='worker-node-0', + retry_strategy={'strategy': 'bounded', 'max_attempts': 3} +) +response = client.jobs.create(raw_request) +``` + ### Waiting for Completion ```python @@ -317,8 +411,8 @@ if response.next_cursor: try: final_job = client.jobs.wait_for_completion( job_id=123, - poll_interval=5.0, # Check every 5 seconds - timeout=3600.0 # Give up after 1 hour + poll_interval=5, # Check every 5 seconds + timeout=3600 # Give up after 1 hour (None = infinite) ) if final_job.status == 'Completed': @@ -330,6 +424,38 @@ except TimeoutError as e: print(f"Job did not complete in time: {e}") ``` +### Monitoring Job Progress + +```python +# Get per-table progress +progress = client.jobs.get_progress(123) +print(f"Job {progress.job_id}: {progress.job_status}") + +for table, info in progress.tables.items(): + print(f" {table}:") + print(f" Blocks: {info.start_block} -> {info.current_block}") + print(f" Files: {info.files_count}") + print(f" Size: {info.total_size_bytes} bytes") + +# Check for error details +if progress.detail: + print(f"Error detail: {progress.detail}") +``` + +### Job Lifecycle Events + +```python +# List all events for a job +events = client.jobs.get_events(123) +for event in events.events: + print(f"{event.created_at}: {event.event_type} (node: {event.node_id})") + +# Get detailed info for a specific event +event_detail = client.jobs.get_event(123, event_id=1) +print(f"Type: {event_detail.event_type}") +print(f"Detail: {event_detail.detail}") +``` + ### Stopping Jobs ```python @@ -340,11 +466,16 @@ client.jobs.stop(123) ### Deleting Jobs ```python -# Delete a single job +# Delete a single job (must be in terminal state) client.jobs.delete(123) -# Delete multiple jobs -client.jobs.delete_many([123, 124, 125]) +# Delete all completed jobs +client.jobs.delete_by_status('Completed') + +# Delete all terminal jobs (completed, stopped, and errored) +client.jobs.delete_by_status('Terminal') + +# Other status filters: 'Stopped', 'Error' ``` ## Schema Validation @@ -352,16 +483,21 @@ client.jobs.delete_many([123, 124, 125]) The schema client validates SQL queries and returns their output schemas without execution: ```python -# Validate a query and get its schema -schema_response = client.schema.get_output_schema( - sql_query='SELECT block_num, hash, timestamp FROM eth.blocks WHERE block_num > 1000000', - is_sql_dataset=True +# Analyze a query with dependencies +response = client.schema.analyze( + dependencies={'eth': '_/eth_firehose@0.0.0'}, + tables={ + 'blocks': 'SELECT block_num, hash, timestamp FROM eth.blocks WHERE block_num > 1000000' + } ) -# Inspect the Arrow schema -print(schema_response.schema) +# Inspect the schemas (one per table) +for table_name, schema in response.schemas.items(): + print(f"{table_name}: {schema}") ``` +> **Note:** The `dependencies` parameter requires exact version references or manifest hashes. Symbolic references like `"latest"` or `"dev"` are not allowed. + This is particularly useful for: - Validating queries before registration @@ -386,20 +522,6 @@ manifest = query.to_manifest( table_name='blocks', network='mainnet' ) - -print(manifest) -# { -# 'kind': 'manifest', -# 'dependencies': {'eth': '_/eth_firehose@1.0.0'}, -# 'tables': { -# 'blocks': { -# 'input': {'sql': 'SELECT block_num, hash FROM eth.blocks'}, -# 'schema': {'arrow': {...}}, # Auto-fetched -# 'network': 'mainnet' -# } -# }, -# 'functions': {} -# } ``` ### One-Line Registration and Deployment @@ -479,22 +601,27 @@ client.datasets.register( deploy_resp = client.datasets.deploy( namespace='_', name='tx_counts', - version='0.1.0', + revision='0.1.0', end_block='10000', # Test on first 10k blocks parallelism=2 ) -# 4. Monitor +# 4. Monitor progress +progress = client.jobs.get_progress(deploy_resp.job_id) +for table, info in progress.tables.items(): + print(f"{table}: block {info.current_block}") + +# 5. Wait for completion job = client.jobs.wait_for_completion(deploy_resp.job_id, timeout=600) if job.status == 'Completed': print("Test deployment successful!") - # 5. Deploy full version + # 6. Deploy full version prod_deploy = client.datasets.deploy( namespace='_', name='tx_counts', - version='0.1.0', + revision='0.1.0', end_block='latest', parallelism=8 ) @@ -511,26 +638,24 @@ context = ( ) # Deploy without waiting -deploy_resp = context.deploy( +job = context.deploy( end_block='latest', parallelism=16, wait=False ) -print(f"Started production deployment: {deploy_resp.job_id}") +print(f"Started production deployment: job {job.id}") -# Monitor separately (e.g., in a monitoring service) -def monitor_job(job_id): - while True: - job = client.jobs.get(job_id) - - if job.status in ['Completed', 'Failed', 'Cancelled']: - return job - - print(f"Job {job_id} status: {job.status}") - time.sleep(30) - -final_job = monitor_job(deploy_resp.job_id) +# Monitor progress separately +import time +while True: + progress = client.jobs.get_progress(job.id) + if progress.job_status in ('Completed', 'Failed', 'Stopped'): + print(f"Job finished: {progress.job_status}") + break + for table, info in progress.tables.items(): + print(f" {table}: block {info.current_block}, {info.files_count} files") + time.sleep(30) ``` ### Continuous Deployment @@ -540,7 +665,7 @@ final_job = monitor_job(deploy_resp.job_id) deploy_resp = client.datasets.deploy( namespace='_', name='realtime_data', - version='1.0.0', + revision='1.0.0', parallelism=4 # end_block=None means continuous ) @@ -552,6 +677,97 @@ print(f"Continuous deployment started: {deploy_resp.job_id}") client.jobs.stop(deploy_resp.job_id) ``` +## Revision Management + +Revisions manage physical table storage locations. This is typically used for advanced operations like manually managing table data. + +> **Note:** Revision operations are only available through the `AdminClient` directly, not the unified `Client`. + +```python +from amp.admin import AdminClient + +admin = AdminClient('http://localhost:8080', auth=True) +``` + +### Listing Revisions + +```python +# List all active revisions +revisions = admin.revisions.list(active=True) +for rev in revisions: + print(f"ID: {rev.id}") + print(f" Path: {rev.path}") + print(f" Active: {rev.active}") + print(f" Writer job: {rev.writer}") + if rev.metadata.dataset_name: + print(f" Dataset: {rev.metadata.dataset_namespace}/{rev.metadata.dataset_name}") + print(f" Table: {rev.metadata.table_name}") + +# Pagination +page1 = admin.revisions.list(limit=50) +if page1: + page2 = admin.revisions.list(limit=50, last_id=page1[-1].id) +``` + +### Getting a Revision + +```python +rev = admin.revisions.get(42) +print(f"Path: {rev.path}") +print(f"Active: {rev.active}") +print(f"Writer: {rev.writer}") +``` + +### Creating Revisions + +```python +result = admin.revisions.create( + dataset='_/eth_firehose@0.0.0', + table_name='blocks', + storage_path='s3://my-bucket/revisions/blocks-v2' +) +print(f"Created revision with location ID: {result.location_id}") +``` + +### Activating and Deactivating + +```python +# Activate a revision (makes it the live data source for queries) +admin.revisions.activate(42, '_/eth_firehose@0.0.0', 'blocks') + +# Deactivate the current revision for a table +admin.revisions.deactivate('_/eth_firehose@0.0.0', 'blocks') +``` + +### Pruning and Truncating + +```python +# Prune non-canonical files (schedule for garbage collection) +result = admin.revisions.prune(42) +print(f"Scheduled {result.files_scheduled} files for GC (delay: {result.gc_delay_secs}s)") + +# Prune only files before a specific block +result = admin.revisions.prune(42, before_block=1000000) + +# Truncate (delete all files immediately) +result = admin.revisions.truncate(42) +print(f"Deleted {result.files_deleted} files") +``` + +### Restoring Revisions + +```python +# Restore files for a revision +result = admin.revisions.restore(42) +print(f"Restored {result.total_files} files") +``` + +### Deleting Revisions + +```python +admin.revisions.delete(42) +``` + ## Error Handling The admin client provides typed exceptions for different error scenarios: @@ -565,6 +781,8 @@ from amp.admin.errors import ( InvalidManifestError, JobNotFoundError, DependencyValidationError, + SchedulerError, + RevisionNotFoundError, InternalServerError, ) ``` @@ -596,7 +814,7 @@ def robust_deploy(client, namespace, name, version, **deploy_options): # Check if dataset exists try: version_info = client.datasets.get_version(namespace, name, version) - print(f"Found existing version: {version_info.manifest_hash}") + print(f"Found dataset: {version_info.kind}, hash: {version_info.manifest_hash}") except DatasetNotFoundError: raise ValueError(f"Dataset {namespace}/{name}@{version} not registered") @@ -605,22 +823,22 @@ def robust_deploy(client, namespace, name, version, **deploy_options): namespace, name, version, **deploy_options ) - # Wait for completion - job = client.jobs.wait_for_completion( - deploy_resp.job_id, - poll_interval=5.0, - timeout=3600.0 - ) + # Wait for completion with progress monitoring + import time + while True: + progress = client.jobs.get_progress(deploy_resp.job_id) - if job.status == 'Completed': - print(f"Deployment successful: job {job.id}") - return job - else: - raise RuntimeError(f"Job failed with status: {job.status}") + if progress.job_status in ('Completed', 'Failed', 'Stopped'): + job = client.jobs.get(deploy_resp.job_id) + if job.status == 'Completed': + print(f"Deployment successful: job {job.id}") + return job + else: + raise RuntimeError(f"Job failed with status: {job.status}") - except TimeoutError: - print("Deployment timeout - job may still be running") - raise + for table, info in progress.tables.items(): + print(f" {table}: block {info.current_block}") + time.sleep(5) except AdminAPIError as e: print(f"API error during deployment: {e.message}") @@ -639,23 +857,33 @@ job = robust_deploy( ## Best Practices -### 1. Use Context Managers +### 1. Use Auth File for Authentication ```python -with Client(query_url=..., admin_url=..., auth_token=...) as client: - # Client will automatically close connections +# Recommended: shared with TS CLI, auto-refreshing +client = Client(query_url=..., admin_url=..., auth=True) +``` + +### 2. Use Context Managers + +```python +with Client(query_url=..., admin_url=..., auth=True) as client: client.datasets.register(...) +# Connection automatically closed ``` -### 2. Validate Schemas Early +### 3. Validate Schemas Early ```python # Validate before registration -schema = client.schema.get_output_schema(sql_query, True) -print(f"Query will produce {len(schema.schema['fields'])} columns") +response = client.schema.analyze( + dependencies={'eth': '_/eth_firehose@0.0.0'}, + tables={'my_table': 'SELECT block_num, hash FROM eth.blocks'} +) +print(f"Columns: {response.schemas}") ``` -### 3. Version Your Datasets +### 4. Version Your Datasets ```python # Use semantic versioning @@ -668,37 +896,30 @@ client.datasets.register('_', 'my_dataset', '1.1.0', manifest_v1_1) # Added col client.datasets.register('_', 'my_dataset', '2.0.0', manifest_v2) # Breaking change ``` -### 4. Monitor Long-Running Jobs +### 5. Monitor Long-Running Jobs ```python -# Don't block main thread for long deployments -deploy_resp = client.datasets.deploy(..., wait=False) - -# Monitor asynchronously -import threading - -def monitor(): - job = client.jobs.wait_for_completion(deploy_resp.job_id) - print(f"Job finished: {job.status}") +# Use get_progress for detailed monitoring +deploy_resp = client.datasets.deploy(...) -thread = threading.Thread(target=monitor) -thread.start() +progress = client.jobs.get_progress(deploy_resp.job_id) +for table, info in progress.tables.items(): + print(f"{table}: block {info.current_block}, {info.files_count} files") ``` -### 5. Handle Dependencies Correctly +### 6. Handle Dependencies Correctly ```python -# Always specify full dependency references +# Always specify full dependency references with exact versions query = ( client.sql("SELECT * FROM base.data") .with_dependency('base', '_/base_dataset@1.0.0') # Include version! ) -# Not: .with_dependency('base', 'base_dataset') # ❌ Missing namespace/version +# Not: .with_dependency('base', 'base_dataset') # Missing namespace/version ``` ## Next Steps - See [API Reference](api/client_api.md) for complete API documentation - Check [examples/admin/](../examples/admin/) for more code samples -- Review the [Admin API OpenAPI spec](../specs/admin.spec.json) for endpoint details diff --git a/docs/api/client_api.md b/docs/api/client_api.md index d03763a..c78924b 100644 --- a/docs/api/client_api.md +++ b/docs/api/client_api.md @@ -1,6 +1,6 @@ # Client API Reference -Complete API reference for the Amp Admin Client. +Complete API reference for the Amp Python client. ## Table of Contents @@ -10,6 +10,7 @@ Complete API reference for the Amp Admin Client. - [DatasetsClient](#datasetsclient) - [JobsClient](#jobsclient) - [SchemaClient](#schemaclient) + - [RevisionsClient](#revisionsclient) - [Data Models](#data-models) - [Error Classes](#error-classes) - [Helper Classes](#helper-classes) @@ -31,35 +32,52 @@ Client( url: Optional[str] = None, query_url: Optional[str] = None, admin_url: Optional[str] = None, - auth_token: Optional[str] = None + registry_url: str = 'https://api.registry.amp.staging.thegraph.com', + auth_token: Optional[str] = None, + auth: bool = False ) ``` **Parameters:** - `url` (str, optional): Legacy parameter for Flight SQL URL. If provided and `query_url` is not, this value is used for `query_url`. -- `query_url` (str, optional): Query endpoint URL via Flight SQL (e.g., `"grpc://localhost:8815"`). +- `query_url` (str, optional): Query endpoint URL via Flight SQL (e.g., `"grpc://localhost:1602"`). - `admin_url` (str, optional): Admin API HTTP endpoint URL (e.g., `"http://localhost:8080"`). -- `auth_token` (str, optional): Authentication token for Admin API requests. +- `registry_url` (str, optional): Registry API URL. Defaults to staging registry. +- `auth_token` (str, optional): Bearer token for authentication (highest priority). +- `auth` (bool, optional): If True, load auth token from `~/.amp/cache` (shared with TS CLI). + +**Authentication Priority (highest to lowest):** + +1. Explicit `auth_token` parameter +2. `AMP_AUTH_TOKEN` environment variable +3. `auth=True` - reads from `~/.amp/cache/amp_cli_auth` **Raises:** -- `ValueError`: When accessing admin properties without configuring `admin_url`. +- `ValueError`: When accessing admin/registry properties without configuring the respective URL. **Example:** ```python from amp import Client -# Full configuration +# Full configuration with auth file client = Client( - query_url="grpc://localhost:8815", + query_url="grpc://localhost:1602", admin_url="http://localhost:8080", - auth_token="my-token" + auth=True ) # Query-only (backward compatible) -client = Client(url="grpc://localhost:8815") +client = Client(url="grpc://localhost:1602") + +# With explicit token +client = Client( + query_url="grpc://localhost:1602", + admin_url="http://localhost:8080", + auth_token="my-token" +) ``` #### Properties @@ -88,6 +106,14 @@ Access the SchemaClient for schema operations. **Raises:** `ValueError` if `admin_url` was not configured. +##### `registry` + +Access the RegistryClient for dataset discovery and search. + +**Returns:** `RegistryClient` + +**Raises:** `ValueError` if `registry_url` was not configured. + #### Methods ##### `sql(sql: str) -> QueryBuilder` @@ -120,24 +146,41 @@ Low-level HTTP client for the Admin API. Typically you'll use the unified `Clien ```python AdminClient( base_url: str, - auth_token: Optional[str] = None + auth_token: Optional[str] = None, + auth: bool = False ) ``` **Parameters:** - `base_url` (str): Base URL for the Admin API (e.g., `"http://localhost:8080"`). -- `auth_token` (str, optional): Authentication token. If provided, adds `Authorization: Bearer ` header. +- `auth_token` (str, optional): Bearer token for authentication. +- `auth` (bool, optional): If True, load auth token from `~/.amp/cache` (auto-refreshing). + +**Raises:** + +- `ValueError`: If both `auth=True` and `auth_token` are provided. + +**Authentication Priority (highest to lowest):** + +1. Explicit `auth_token` parameter +2. `AMP_AUTH_TOKEN` environment variable +3. `auth=True` - reads from `~/.amp/cache/amp_cli_auth` **Example:** ```python from amp.admin import AdminClient -admin = AdminClient( - base_url="http://localhost:8080", - auth_token="my-token" -) +# With auth file (auto-refreshing) +admin = AdminClient('http://localhost:8080', auth=True) + +# With explicit token +admin = AdminClient('http://localhost:8080', auth_token='your-token') + +# With environment variable +# export AMP_AUTH_TOKEN="eyJhbGci..." +admin = AdminClient('http://localhost:8080') ``` #### Properties @@ -160,24 +203,42 @@ Access the SchemaClient. **Returns:** `SchemaClient` +##### `revisions` + +Access the RevisionsClient for table revision operations. + +**Returns:** `RevisionsClient` + #### Methods -##### `close()` +##### `list_manifests()` -Close the HTTP client connection. +List all manifests in the system. + +```python +list_manifests() -> models.ManifestsResponse +``` + +**Returns:** `ManifestsResponse` with list of `ManifestInfo` objects. **Example:** ```python -admin.close() +response = admin.list_manifests() +for manifest in response.manifests: + print(f"{manifest.hash}: {manifest.kind} ({manifest.dataset_count} datasets)") ``` +##### `close()` + +Close the HTTP client connection. + #### Context Manager AdminClient can be used as a context manager: ```python -with AdminClient("http://localhost:8080") as admin: +with AdminClient("http://localhost:8080", auth=True) as admin: admin.datasets.list_all() # Connection automatically closed ``` @@ -194,13 +255,13 @@ Client for dataset registration, deployment, and management operations. ##### `register()` -Register a new dataset or dataset version. +Register a new dataset manifest. ```python register( namespace: str, name: str, - version: Optional[str], + version: str, manifest: dict ) -> None ``` @@ -209,13 +270,14 @@ register( - `namespace` (str): Dataset namespace (e.g., `"_"`). - `name` (str): Dataset name. -- `version` (str, optional): Semantic version string (e.g., `"1.0.0"`). If not provided, server assigns version. +- `version` (str): Semantic version (e.g., `"1.0.0"`) or tag (`"latest"`, `"dev"`). - `manifest` (dict): Dataset manifest dictionary. **Raises:** - `InvalidManifestError`: If manifest validation fails. - `DependencyValidationError`: If referenced dependencies don't exist. +- `ManifestRegistrationError`: If registration fails. **Example:** @@ -238,9 +300,12 @@ Deploy a registered dataset version. deploy( namespace: str, name: str, - version: str, + revision: str, + end_block: Optional[str] = None, parallelism: Optional[int] = None, - end_block: Optional[str] = None + retry_strategy: Optional[dict] = None, + verify: Optional[bool] = None, + worker_id: Optional[str] = None ) -> models.DeployResponse ``` @@ -248,15 +313,23 @@ deploy( - `namespace` (str): Dataset namespace. - `name` (str): Dataset name. -- `version` (str): Version to deploy. -- `parallelism` (int, optional): Number of parallel workers. -- `end_block` (str, optional): Block to stop at (e.g., `"latest"`, `"1000000"`). If not provided, runs continuously. +- `revision` (str): Version tag (`"latest"`, `"dev"`, `"1.0.0"`, etc.). +- `end_block` (str, optional): Block to stop at. Supports: + - `None`: Continuous mode (never stops) + - `"latest"`: Stop at the latest block when the job starts + - A positive number string (e.g., `"1000000"`): Stop at absolute block number + - A negative number string (e.g., `"-100"`): Stop at latest minus N blocks +- `parallelism` (int, optional): Number of parallel workers. Only applicable to raw datasets. Defaults to 1. +- `retry_strategy` (dict, optional): Retry strategy controlling how failed jobs are retried. Supports `"none"`, `"bounded"` (with `max_attempts`), and `"unless_stopped"`. +- `verify` (bool, optional): Enable cryptographic verification of EVM block data (hashes, transaction roots, receipt roots). Defaults to False. +- `worker_id` (str, optional): Worker selector - exact ID (e.g., `"worker-node-0"`) or glob pattern (e.g., `"worker-eth-*"`). **Returns:** `DeployResponse` with `job_id` field. **Raises:** - `DatasetNotFoundError`: If dataset/version doesn't exist. +- `SchedulerError`: If deployment fails. **Example:** @@ -264,7 +337,9 @@ deploy( response = client.datasets.deploy( '_', 'my_dataset', '1.0.0', parallelism=4, - end_block='latest' + end_block='latest', + verify=True, + worker_id='worker-eth-*' ) print(f"Job ID: {response.job_id}") ``` @@ -274,10 +349,10 @@ print(f"Job ID: {response.job_id}") List all registered datasets. ```python -list_all() -> models.ListDatasetsResponse +list_all() -> models.DatasetsResponse ``` -**Returns:** `ListDatasetsResponse` containing list of `DatasetSummary` objects. +**Returns:** `DatasetsResponse` containing list of `DatasetSummary` objects. **Example:** @@ -304,7 +379,7 @@ get_versions( - `namespace` (str): Dataset namespace. - `name` (str): Dataset name. -**Returns:** `VersionsResponse` with `versions` list and `special_tags` dict. +**Returns:** `VersionsResponse` with `versions` list and `special_tags`. **Raises:** @@ -328,17 +403,17 @@ Get details of a specific dataset version. get_version( namespace: str, name: str, - version: str -) -> models.VersionInfo + revision: str +) -> models.DatasetInfo ``` **Parameters:** - `namespace` (str): Dataset namespace. - `name` (str): Dataset name. -- `version` (str): Version string. +- `revision` (str): Version tag or semantic version. -**Returns:** `VersionInfo` with version metadata. +**Returns:** `DatasetInfo` with dataset details including kind, manifest_hash, tables, start_block, and more. **Raises:** @@ -348,8 +423,10 @@ get_version( ```python info = client.datasets.get_version('_', 'eth_blocks', '1.0.0') +print(f"Kind: {info.kind}") print(f"Manifest hash: {info.manifest_hash}") -print(f"Created: {info.created_at}") +print(f"Tables: {info.tables}") +print(f"Start block: {info.start_block}") ``` ##### `get_manifest()` @@ -360,7 +437,7 @@ Retrieve the manifest for a specific dataset version. get_manifest( namespace: str, name: str, - version: str + revision: str ) -> dict ``` @@ -368,7 +445,7 @@ get_manifest( - `namespace` (str): Dataset namespace. - `name` (str): Dataset name. -- `version` (str): Version string. +- `revision` (str): Version tag or semantic version. **Returns:** Manifest dictionary. @@ -383,14 +460,116 @@ manifest = client.datasets.get_manifest('_', 'eth_blocks', '1.0.0') print(f"Tables: {list(manifest['tables'].keys())}") ``` -##### `delete()` +##### `describe()` -Delete a dataset and all its versions. +Get a structured summary of tables and columns in a dataset. ```python -delete( +describe( namespace: str, - name: str + name: str, + revision: str = 'latest' +) -> dict[str, list[dict[str, str | bool]]] +``` + +**Parameters:** + +- `namespace` (str): Dataset namespace. +- `name` (str): Dataset name. +- `revision` (str, optional): Version tag. Default: `"latest"`. + +**Returns:** Dictionary mapping table names to lists of column info dicts with `name`, `type`, and `nullable` keys. + +**Example:** + +```python +schema = client.datasets.describe('_', 'eth_firehose', 'latest') +for table_name, columns in schema.items(): + print(f"\nTable: {table_name}") + for col in columns: + nullable = "NULL" if col['nullable'] else "NOT NULL" + print(f" {col['name']}: {col['type']} {nullable}") +``` + +##### `inspect()` + +Pretty-print the structure of a dataset. + +```python +inspect( + namespace: str, + name: str, + revision: str = 'latest' +) -> None +``` + +**Example:** + +```python +client.datasets.inspect('_', 'eth_firehose') +# Dataset: _/eth_firehose@latest +# Kind: evm-rpc +# +# blocks (21 columns) +# block_num UInt64 NOT NULL +# timestamp Timestamp NOT NULL +# ... +``` + +##### `list_jobs()` + +List jobs for a specific dataset version. + +```python +list_jobs( + namespace: str, + name: str, + revision: str +) -> models.JobsResponse +``` + +**Returns:** `JobsResponse` with jobs for this dataset version. + +**Example:** + +```python +jobs = client.datasets.list_jobs('_', 'eth_firehose', 'latest') +for job in jobs.jobs: + print(f'{job.id}: {job.status}') +``` + +##### `restore()` + +Restore physical tables for a dataset version. + +```python +restore( + namespace: str, + name: str, + revision: str +) -> models.RestoreResponse +``` + +**Returns:** `RestoreResponse` with `total_files` restored. + +**Example:** + +```python +result = client.datasets.restore('_', 'eth_firehose', 'latest') +print(f'Restored {result.total_files} files') +``` + +##### `restore_table()` + +Restore a specific table for a dataset version. + +```python +restore_table( + namespace: str, + name: str, + revision: str, + table_name: str, + location_id: Optional[int] = None ) -> None ``` @@ -398,10 +577,26 @@ delete( - `namespace` (str): Dataset namespace. - `name` (str): Dataset name. +- `revision` (str): Version tag or semantic version. +- `table_name` (str): Table to restore. +- `location_id` (int, optional): Location ID of the revision to activate. If omitted, the latest revision is discovered from object storage. -**Raises:** +**Example:** -- `DatasetNotFoundError`: If dataset doesn't exist. +```python +client.datasets.restore_table('_', 'eth_firehose', 'latest', 'blocks') +``` + +##### `delete()` + +Delete a dataset and all its versions. + +```python +delete( + namespace: str, + name: str +) -> None +``` **Example:** @@ -409,6 +604,24 @@ delete( client.datasets.delete('_', 'old_dataset') ``` +##### `delete_version()` + +Delete a specific version of a dataset. + +```python +delete_version( + namespace: str, + name: str, + version: str +) -> None +``` + +**Example:** + +```python +client.datasets.delete_version('_', 'my_dataset', '1.0.0') +``` + --- ### JobsClient @@ -427,10 +640,6 @@ Get details of a specific job. get(job_id: int) -> models.JobInfo ``` -**Parameters:** - -- `job_id` (int): Job ID. - **Returns:** `JobInfo` with job details. **Raises:** @@ -443,6 +652,7 @@ get(job_id: int) -> models.JobInfo job = client.jobs.get(123) print(f"Status: {job.status}") print(f"Node: {job.node_id}") +print(f"Created: {job.created_at}") ``` ##### `list()` @@ -451,17 +661,17 @@ List jobs with pagination. ```python list( - limit: int = 100, + limit: int = 50, last_job_id: Optional[int] = None -) -> models.ListJobsResponse +) -> models.JobsResponse ``` **Parameters:** -- `limit` (int, optional): Maximum number of jobs to return. Default: 100. +- `limit` (int, optional): Maximum number of jobs to return. Default: 50, max: 1000. - `last_job_id` (int, optional): Cursor for pagination. Returns jobs after this ID. -**Returns:** `ListJobsResponse` with `jobs` list and optional `next_cursor`. +**Returns:** `JobsResponse` with `jobs` list and optional `next_cursor`. **Example:** @@ -476,6 +686,35 @@ if response.next_cursor: next_page = client.jobs.list(limit=50, last_job_id=response.next_cursor) ``` +##### `create()` + +Create a new job. + +```python +create(request: models.CreateJobRequest) -> models.CreateJobResponse +``` + +**Parameters:** + +- `request`: Job creation request. Dispatches on the `kind` field: + - `CreateJobRequest1(kind=Kind.gc)` - Garbage collection job + - `CreateJobRequest2(kind=Kind1.materialize_raw)` - Raw dataset materialization + - `CreateJobRequest3(kind=Kind2.materialize_derived)` - Derived dataset materialization + +All variants accept optional `retry_strategy` and `worker_id` parameters. + +**Returns:** `CreateJobResponse` with `job_id`. + +**Example:** + +```python +from amp.admin.models import CreateJobRequest2, Kind1 + +request = CreateJobRequest2(kind=Kind1.materialize_raw) +response = client.jobs.create(request) +print(f'Job ID: {response.job_id}') +``` + ##### `wait_for_completion()` Poll job status until completion or timeout. @@ -483,16 +722,16 @@ Poll job status until completion or timeout. ```python wait_for_completion( job_id: int, - poll_interval: float = 5.0, - timeout: float = 3600.0 + poll_interval: int = 5, + timeout: Optional[int] = None ) -> models.JobInfo ``` **Parameters:** - `job_id` (int): Job ID to monitor. -- `poll_interval` (float, optional): Seconds between status checks. Default: 5.0. -- `timeout` (float, optional): Maximum seconds to wait. Default: 3600.0 (1 hour). +- `poll_interval` (int, optional): Seconds between status checks. Default: 5. +- `timeout` (int, optional): Maximum seconds to wait. Default: None (infinite). **Returns:** `JobInfo` with final job status. @@ -507,8 +746,8 @@ wait_for_completion( try: job = client.jobs.wait_for_completion( job_id=123, - poll_interval=5.0, - timeout=1800.0 # 30 minutes + poll_interval=5, + timeout=1800 # 30 minutes ) if job.status == 'Completed': @@ -522,19 +761,16 @@ except TimeoutError: ##### `stop()` -Stop a running job. +Stop a running job. The job will transition through StopRequested and Stopping states before reaching Stopped. ```python stop(job_id: int) -> None ``` -**Parameters:** - -- `job_id` (int): Job ID to stop. - **Raises:** - `JobNotFoundError`: If job doesn't exist. +- `JobStopError`: If stop request fails. **Example:** @@ -544,19 +780,16 @@ client.jobs.stop(123) ##### `delete()` -Delete a single job. +Delete a job in terminal state (Completed, Failed, or Stopped). ```python delete(job_id: int) -> None ``` -**Parameters:** - -- `job_id` (int): Job ID to delete. - **Raises:** - `JobNotFoundError`: If job doesn't exist. +- `JobDeleteError`: If job is not in terminal state or deletion fails. **Example:** @@ -564,22 +797,80 @@ delete(job_id: int) -> None client.jobs.delete(123) ``` -##### `delete_many()` +##### `delete_by_status()` -Delete multiple jobs. +Delete all jobs matching a status filter. ```python -delete_many(job_ids: list[int]) -> None +delete_by_status(status: str) -> None ``` **Parameters:** -- `job_ids` (list[int]): List of job IDs to delete. +- `status` (str): Status filter - one of `"Terminal"`, `"Completed"`, `"Stopped"`, `"Error"`. + +**Example:** + +```python +# Delete all completed jobs +client.jobs.delete_by_status('Completed') + +# Delete all terminal jobs (completed, stopped, and errored) +client.jobs.delete_by_status('Terminal') +``` + +##### `get_events()` + +Get lifecycle events for a job. + +```python +get_events(job_id: int) -> models.JobEventsResponse +``` + +**Returns:** `JobEventsResponse` with list of `JobEventInfo` objects. **Example:** ```python -client.jobs.delete_many([123, 124, 125]) +events = client.jobs.get_events(123) +for event in events.events: + print(f'{event.event_type} at {event.created_at} (node: {event.node_id})') +``` + +##### `get_event()` + +Get a specific lifecycle event with full detail. + +```python +get_event(job_id: int, event_id: int) -> models.JobEventDetailResponse +``` + +**Returns:** `JobEventDetailResponse` with event details including optional structured `detail` payload. + +**Example:** + +```python +event = client.jobs.get_event(123, 1) +print(f'{event.event_type}: {event.detail}') +``` + +##### `get_progress()` + +Get per-table progress information for a job. + +```python +get_progress(job_id: int) -> models.JobProgressResponse +``` + +**Returns:** `JobProgressResponse` with per-table progress including block numbers and file statistics. + +**Example:** + +```python +progress = client.jobs.get_progress(123) +print(f"Job status: {progress.job_status}") +for table, info in progress.tables.items(): + print(f" {table}: block {info.current_block}, {info.files_count} files, {info.total_size_bytes} bytes") ``` --- @@ -592,23 +883,27 @@ Client for SQL query validation and schema inference. #### Methods -##### `get_output_schema()` +##### `analyze()` -Validate SQL query and get its output Arrow schema without executing it. +Validate SQL queries and infer output schemas without executing them. ```python -get_output_schema( - sql_query: str, - is_sql_dataset: bool = True -) -> models.OutputSchemaResponse +analyze( + dependencies: Optional[dict[str, str]] = None, + functions: Optional[dict[str, Any]] = None, + tables: Optional[dict[str, str]] = None +) -> models.SchemaResponse ``` **Parameters:** -- `sql_query` (str): SQL query to analyze. -- `is_sql_dataset` (bool, optional): Whether this is for a SQL dataset. Default: True. +- `dependencies` (dict, optional): External dataset dependencies mapped by alias (e.g., `{'eth': '_/eth_firehose@0.0.0'}`). Symbolic references like `"latest"` or `"dev"` are not allowed. +- `functions` (dict, optional): User-defined function definitions mapped by name. +- `tables` (dict, optional): Table definitions as SQL queries mapped by table name. -**Returns:** `OutputSchemaResponse` with Arrow schema. +At least one of `tables` or `functions` must be provided. + +**Returns:** `SchemaResponse` with `schemas` dict mapping table names to inferred schemas. **Raises:** @@ -618,16 +913,198 @@ get_output_schema( **Example:** ```python -response = client.schema.get_output_schema( - 'SELECT block_num, hash FROM eth.blocks WHERE block_num > 1000000', - is_sql_dataset=True +response = client.schema.analyze( + dependencies={'eth': '_/eth_firehose@0.0.0'}, + tables={'blocks': 'SELECT block_num, hash FROM eth.blocks'} ) -print(response.schema) # Arrow schema dict +print(response.schemas['blocks']) ``` --- +### RevisionsClient + +Client for managing physical table revisions (storage locations). + +**Module:** `amp.admin.revisions` + +> **Note:** This client is only available via `AdminClient.revisions`, not through the unified `Client` class. + +#### Methods + +##### `list()` + +List table revisions with optional filtering. + +```python +list( + active: Optional[bool] = None, + limit: Optional[int] = None, + last_id: Optional[int] = None +) -> list[models.RevisionInfo] +``` + +**Parameters:** + +- `active` (bool, optional): Filter by active status. +- `limit` (int, optional): Maximum number of revisions to return (default: 100). +- `last_id` (int, optional): Cursor for pagination. + +**Returns:** List of `RevisionInfo` objects. + +**Example:** + +```python +revisions = admin.revisions.list(active=True, limit=50) +for rev in revisions: + print(f'{rev.id}: {rev.path} (active={rev.active})') +``` + +##### `get()` + +Get a specific revision by ID. + +```python +get(revision_id: int) -> models.RevisionInfo +``` + +**Example:** + +```python +rev = admin.revisions.get(42) +print(f'Path: {rev.path}, Active: {rev.active}, Writer: {rev.writer}') +``` + +##### `create()` + +Create a new table revision. + +```python +create( + dataset: str, + table_name: str, + storage_path: str +) -> models.CreateRevisionResponse +``` + +**Parameters:** + +- `dataset` (str): Dataset reference (e.g., `"_/eth_firehose@0.0.0"`). +- `table_name` (str): Table name. +- `storage_path` (str): Revision path in object storage. + +**Returns:** `CreateRevisionResponse` with `location_id`. + +**Example:** + +```python +result = admin.revisions.create('_/eth_firehose@0.0.0', 'blocks', 's3://bucket/path') +print(f'Location ID: {result.location_id}') +``` + +##### `delete()` + +Delete a revision. + +```python +delete(revision_id: int) -> None +``` + +##### `prune()` + +Prune non-canonical files from a revision. + +```python +prune( + revision_id: int, + before_block: Optional[int] = None, + gc_delay_secs: Optional[int] = None +) -> models.PruneResponse +``` + +**Parameters:** + +- `revision_id` (int): Revision (location) ID. +- `before_block` (int, optional): Only prune files before this block number. +- `gc_delay_secs` (int, optional): Seconds before files become eligible for GC deletion. + +**Returns:** `PruneResponse` with `files_scheduled` and `gc_delay_secs`. + +**Example:** + +```python +result = admin.revisions.prune(42) +print(f'Scheduled {result.files_scheduled} files for GC') +``` + +##### `truncate()` + +Truncate all files from a revision. + +```python +truncate( + revision_id: int, + concurrency: Optional[int] = None +) -> models.TruncateResponse +``` + +**Returns:** `TruncateResponse` with `files_deleted` count. + +**Example:** + +```python +result = admin.revisions.truncate(42) +print(f'Deleted {result.files_deleted} files') +``` + +##### `activate()` + +Activate a table revision. + +```python +activate( + revision_id: int, + dataset: str, + table_name: str +) -> None +``` + +**Example:** + +```python +admin.revisions.activate(42, '_/eth_firehose@0.0.0', 'blocks') +``` + +##### `deactivate()` + +Deactivate a table revision. + +```python +deactivate( + dataset: str, + table_name: str +) -> None +``` + +**Example:** + +```python +admin.revisions.deactivate('_/eth_firehose@0.0.0', 'blocks') +``` + +##### `restore()` + +Restore files for a revision. + +```python +restore(revision_id: int) -> models.RestoreResponse +``` + +**Returns:** `RestoreResponse` with `total_files` restored. + +--- + ## Data Models All data models are Pydantic v2 models defined in `amp.admin.models`. @@ -642,17 +1119,32 @@ Summary information about a dataset. - `namespace` (str): Dataset namespace - `name` (str): Dataset name -- `latest_version` (str): Latest version string -- `versions` (list[str]): All available versions +- `latest_version` (str, optional): Latest semantic version (if any) +- `versions` (list[str]): All semantic versions (sorted descending) -#### `VersionInfo` +#### `DatasetInfo` Detailed information about a dataset version. **Fields:** -- `version` (str): Version string -- `manifest_hash` (str): Hash of the manifest +- `namespace` (str): Dataset namespace +- `name` (str): Dataset name +- `kind` (str): Dataset kind (e.g., `"evm-rpc"`, `"manifest"`) +- `manifest_hash` (str): Manifest hash +- `tables` (list[str]): Table names +- `start_block` (int): Starting block number +- `revision` (str): Revision requested +- `finalized_blocks_only` (bool): Whether dataset uses finalized blocks only + +#### `VersionInfo` + +Version information for a dataset. + +**Fields:** + +- `version` (str): Semantic version +- `manifest_hash` (str): Manifest hash for this version - `created_at` (str): ISO timestamp - `updated_at` (str): ISO timestamp @@ -664,7 +1156,7 @@ Response containing all versions of a dataset. - `namespace` (str): Dataset namespace - `name` (str): Dataset name -- `versions` (list[VersionInfo]): List of version details +- `versions` (list[VersionInfo]): List of version details (sorted descending) - `special_tags` (SpecialTags): Special version tags #### `SpecialTags` @@ -673,8 +1165,8 @@ Special version tags for a dataset. **Fields:** -- `latest` (str): Latest stable version -- `dev` (str, optional): Development version +- `latest` (str, optional): Latest stable version +- `dev` (str, optional): Development version (points to manifest hash) #### `JobInfo` @@ -683,11 +1175,13 @@ Information about a job. **Fields:** - `id` (int): Job ID -- `status` (str): Job status (`"Pending"`, `"Running"`, `"Completed"`, `"Failed"`, `"Cancelled"`) -- `descriptor` (dict): Job configuration -- `node_id` (str, optional): Worker node ID +- `status` (str): Job status (`"Scheduled"`, `"Running"`, `"Completed"`, `"Stopped"`, `"Failed"`) +- `descriptor` (Any): Job configuration as JSON +- `node_id` (str): Worker node ID +- `created_at` (str): ISO timestamp +- `updated_at` (str): ISO timestamp -#### `ListJobsResponse` +#### `JobsResponse` Response from listing jobs. @@ -696,7 +1190,7 @@ Response from listing jobs. - `jobs` (list[JobInfo]): List of jobs - `next_cursor` (int, optional): Cursor for next page -#### `ListDatasetsResponse` +#### `DatasetsResponse` Response from listing datasets. @@ -712,35 +1206,191 @@ Response from deploying a dataset. - `job_id` (int): ID of the created job -#### `OutputSchemaResponse` +#### `RegisterResponse` -Response containing Arrow schema for a query. +Response from registering a dataset. **Fields:** -- `schema` (dict): Arrow schema dictionary +- `namespace` (str): Dataset namespace +- `name` (str): Dataset name +- `kind` (str): Dataset kind +- `manifest_hash` (str): Manifest hash +- `tables` (list[str]): Tables +- `start_block` (int): Starting block +- `finalized_blocks_only` (bool): Finalized blocks only +- `version` (str, optional): Version, if provided -### Request Models +### Job Event & Progress Models -#### `RegisterRequest` +#### `JobEventsResponse` -Request to register a dataset. +Response containing lifecycle events for a job. **Fields:** -- `namespace` (str): Dataset namespace -- `name` (str): Dataset name -- `version` (str, optional): Version string -- `manifest` (dict): Dataset manifest +- `job_id` (int): Job ID +- `events` (list[JobEventInfo]): List of lifecycle events + +#### `JobEventInfo` + +A single job lifecycle event. -#### `OutputSchemaRequest` +**Fields:** + +- `id` (int): Event ID +- `event_type` (str): Event type (e.g., `"SCHEDULED"`, `"RUNNING"`, `"COMPLETED"`, `"ERROR"`, `"FATAL"`, `"STOPPED"`) +- `node_id` (str): Worker node ID +- `created_at` (str): ISO timestamp + +#### `JobEventDetailResponse` -Request to get output schema for a query. +Full detail for a specific event. **Fields:** -- `sql_query` (str): SQL query -- `is_sql_dataset` (bool): Whether this is for a SQL dataset +- `id` (int): Event ID +- `job_id` (int): Job ID +- `event_type` (str): Event type +- `node_id` (str): Worker node ID +- `created_at` (str): ISO timestamp +- `detail` (Any, optional): Structured detail payload + +#### `JobProgressResponse` + +Progress information for a job. + +**Fields:** + +- `job_id` (int): Job ID +- `job_status` (str): Current job status +- `tables` (dict[str, TableProgress]): Per-table progress +- `detail` (Any, optional): Structured error detail (present in error/fatal state) + +#### `TableProgress` + +Progress for a single table. + +**Fields:** + +- `files_count` (int): Number of Parquet files written +- `total_size_bytes` (int): Total size of all files in bytes +- `current_block` (int, optional): Highest block synced (null if no data yet) +- `start_block` (int, optional): Lowest block synced (null if no data yet) + +### Job Creation Models + +#### `CreateJobResponse` + +Response from creating a job. + +**Fields:** + +- `job_id` (int): ID of the scheduled job + +#### `CreateJobRequest` Variants + +Job creation requests dispatch on the `kind` field: + +- `CreateJobRequest1(kind=Kind.gc)` - Garbage collection +- `CreateJobRequest2(kind=Kind1.materialize_raw)` - Raw dataset materialization +- `CreateJobRequest3(kind=Kind2.materialize_derived)` - Derived dataset materialization + +All variants accept: +- `retry_strategy` (dict, optional): Retry strategy +- `worker_id` (str, optional): Worker selector + +### Revision Models + +#### `RevisionInfo` + +Revision (storage location) metadata. + +**Fields:** + +- `id` (int): Location ID +- `path` (str): Relative path to storage location +- `active` (bool): Whether this revision is currently active +- `writer` (int, optional): Writer job ID +- `metadata` (RevisionMetadataInfo): Metadata about the revision + +#### `RevisionMetadataInfo` + +Metadata associated with a revision. + +**Fields:** + +- `dataset_namespace` (str, optional): Dataset namespace +- `dataset_name` (str, optional): Dataset name +- `table_name` (str, optional): Table name +- `manifest_hash` (str, optional): Manifest hash + +#### `CreateRevisionResponse` + +Response from creating a revision. + +**Fields:** + +- `location_id` (int): Location ID assigned to the new revision + +#### `PruneResponse` + +Response from pruning a revision. + +**Fields:** + +- `files_scheduled` (int): Number of files scheduled for GC +- `gc_delay_secs` (int): Seconds before files become eligible for deletion + +#### `TruncateResponse` + +Response from truncating a revision. + +**Fields:** + +- `files_deleted` (int): Number of files deleted from object storage + +#### `RestoreResponse` + +Response from restoring a revision or dataset. + +**Fields:** + +- `total_files` (int): Number of files restored + +### Manifest Models + +#### `ManifestsResponse` + +Response from listing manifests. + +**Fields:** + +- `manifests` (list[ManifestInfo]): List of manifests + +#### `ManifestInfo` + +Summary information for a manifest. + +**Fields:** + +- `hash` (str): Content-addressable SHA-256 hash +- `kind` (str): Dataset kind (e.g., `"evm-rpc"`, `"manifest"`) +- `dataset_count` (int): Number of datasets using this manifest + +### Deploy Request Model + +#### `DeployRequest` + +Full deploy request model (used internally). + +**Fields:** + +- `end_block` (str, optional): End block configuration +- `parallelism` (int, optional): Number of parallel workers +- `retry_strategy` (dict, optional): Retry strategy +- `verify` (bool, optional): Enable cryptographic verification of EVM data +- `worker_id` (str, optional): Worker selector --- @@ -756,7 +1406,7 @@ Base exception for all Admin API errors. **Attributes:** -- `error_code` (str): Error code from API +- `error_code` (str): Machine-readable error code (SCREAMING_SNAKE_CASE) - `message` (str): Human-readable error message - `status_code` (int): HTTP status code @@ -774,16 +1424,41 @@ except AdminAPIError as e: All specific errors inherit from `AdminAPIError`: -- `DatasetNotFoundError`: Dataset or version not found (404) -- `InvalidManifestError`: Manifest validation failed (400) -- `JobNotFoundError`: Job not found (404) -- `DependencyValidationError`: Invalid dependency reference (400) -- `GetOutputSchemaError`: Schema analysis failed (400) -- `InvalidDependencyError`: Malformed dependency specification (400) -- `InternalServerError`: Server error (500) -- `BadGatewayError`: Gateway error (502) -- `ServiceUnavailableError`: Service unavailable (503) -- `GatewayTimeoutError`: Gateway timeout (504) +**Dataset errors:** +- `InvalidPayloadError`: Request JSON is malformed or invalid +- `InvalidManifestError`: Manifest validation failed +- `DatasetNotFoundError`: Dataset or version not found +- `DependencyValidationError`: SQL queries are invalid or reference undeclared dependencies +- `ManifestRegistrationError`: Failed to register manifest +- `ManifestLinkingError`: Failed to link manifest to dataset +- `ManifestNotFoundError`: Manifest hash provided but doesn't exist +- `ManifestValidationError`: Manifest validation failed +- `VersionTaggingError`: Failed to tag manifest with version +- `UnsupportedDatasetKindError`: Dataset kind not supported + +**Job errors:** +- `JobNotFoundError`: Job not found +- `JobStopError`: Failed to stop job +- `JobDeleteError`: Failed to delete job (may be in non-terminal state) +- `JobsDeleteError`: Failed to delete multiple jobs +- `SchedulerError`: Failed to schedule or manage job + +**Revision errors:** +- `RevisionNotFoundError`: Revision not found +- `DeleteRevisionError`: Failed to delete revision +- `PruneError`: Failed to prune revision +- `TruncateError`: Failed to truncate revision +- `ActivateRevisionError`: Failed to activate table revision +- `DeactivateRevisionError`: Failed to deactivate table revision +- `RestoreRevisionError`: Failed to restore table revision + +**Other errors:** +- `EventNotFoundError`: Event not found +- `WorkerNotFoundError`: Worker not found +- `GetOutputSchemaError`: Schema analysis failed +- `InvalidPathError`: Invalid path parameters +- `DatabaseError`: Database operation error +- `InternalServerError`: Internal server error **Usage:** @@ -876,14 +1551,6 @@ register_as( ) -> DeploymentContext ``` -**Parameters:** - -- `namespace` (str): Dataset namespace -- `name` (str): Dataset name -- `version` (str): Version string -- `table_name` (str): Output table name -- `network` (str, optional): Network identifier. Default: `"mainnet"`. - **Returns:** `DeploymentContext` for chaining deployment. **Example:** @@ -913,9 +1580,7 @@ Deploy the registered dataset. deploy( end_block: Optional[str] = None, parallelism: Optional[int] = None, - wait: bool = False, - poll_interval: float = 5.0, - timeout: float = 3600.0 + wait: bool = False ) -> models.JobInfo ``` @@ -924,14 +1589,12 @@ deploy( - `end_block` (str, optional): Block to stop at. If None, runs continuously. - `parallelism` (int, optional): Number of parallel workers. - `wait` (bool, optional): If True, blocks until job completes. Default: False. -- `poll_interval` (float, optional): Seconds between polls if waiting. Default: 5.0. -- `timeout` (float, optional): Maximum wait time if waiting. Default: 3600.0. **Returns:** `JobInfo` - if `wait=False`, returns initial job info; if `wait=True`, returns final job info. -**Raises:** +##### `reference` -- `TimeoutError`: If waiting and job doesn't complete within timeout. +Property returning dataset reference string in format `"{namespace}/{name}@{version}"`. **Example:** @@ -942,7 +1605,7 @@ job = context.deploy(parallelism=4) print(f"Started job {job.id}") # Deploy and wait for completion -job = context.deploy(parallelism=4, wait=True, timeout=1800) +job = context.deploy(parallelism=4, wait=True) print(f"Completed with status: {job.status}") ``` @@ -954,16 +1617,24 @@ Putting it all together: ```python from amp import Client -from amp.admin.errors import AdminAPIError, TimeoutError +from amp.admin.errors import AdminAPIError -# Initialize client +# Initialize client with auth client = Client( - query_url="grpc://localhost:8815", + query_url="grpc://localhost:1602", admin_url="http://localhost:8080", - auth_token="my-token" + auth=True ) try: + # Inspect available datasets + datasets = client.datasets.list_all() + for ds in datasets.datasets: + print(f"{ds.namespace}/{ds.name}@{ds.latest_version}") + + # Inspect a dataset schema + client.datasets.inspect('_', 'eth_firehose') + # Build and test query query = client.sql(""" SELECT block_num, hash, timestamp @@ -971,13 +1642,12 @@ try: WHERE block_num > 1000000 """) - # Test locally - df = query.to_pandas() - print(f"Query returns {len(df)} rows") - # Validate schema - schema = client.schema.get_output_schema(query.query, True) - print(f"Schema: {schema.schema}") + schema = client.schema.analyze( + dependencies={'eth': '_/eth_firehose@0.0.0'}, + tables={'filtered_blocks': 'SELECT block_num, hash FROM eth.blocks WHERE block_num > 1000000'} + ) + print(f"Schema: {schema.schemas}") # Register and deploy job = ( @@ -987,13 +1657,16 @@ try: .deploy( end_block='latest', parallelism=4, - wait=True, - timeout=1800.0 + wait=True ) ) - print(f"Deployment completed: {job.status}") + # Check progress on another job + progress = client.jobs.get_progress(job.id) + for table, info in progress.tables.items(): + print(f" {table}: {info.files_count} files, block {info.current_block}") + except AdminAPIError as e: print(f"API Error: {e.error_code} - {e.message}") @@ -1002,4 +1675,4 @@ except TimeoutError: finally: client.close() -``` +``` \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index d38cfb4..719438e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -160,6 +160,7 @@ exclude = [ [tool.ruff.lint.per-file-ignores] "*_nb.py" = ["B018"] # Notebook files "tests/*" = ["B018", "E712"] # Test files +"src/amp/admin/models.py" = ["E501"] # Auto-generated from OpenAPI spec [tool.ruff.format] quote-style = "single" diff --git a/scripts/fetch_spec.py b/scripts/fetch_spec.py new file mode 100644 index 0000000..41c7fc0 --- /dev/null +++ b/scripts/fetch_spec.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +"""Fetch the latest Admin API OpenAPI spec from the amp server repo. + +Downloads the spec from GitHub and writes it to specs/admin.spec.json. +With --check, compares against the local copy without overwriting (for CI). + +Usage: + uv run python scripts/fetch_spec.py # Download and overwrite + uv run python scripts/fetch_spec.py --check # Check for drift (CI) +""" + +import json +import ssl +import sys +import urllib.request +from pathlib import Path + +SPEC_URL = 'https://raw.githubusercontent.com/edgeandnode/amp/main/docs/schemas/openapi/admin.spec.json' +LOCAL_SPEC = Path('specs/admin.spec.json') + + +def _ssl_context() -> ssl.SSLContext: + """Create an SSL context, using certifi if available.""" + try: + import certifi + + return ssl.create_default_context(cafile=certifi.where()) + except ImportError: + return ssl.create_default_context() + + +def fetch_spec() -> str: + """Download the latest spec from GitHub.""" + print(f'Fetching spec from {SPEC_URL}...') + with urllib.request.urlopen(SPEC_URL, context=_ssl_context()) as response: + return response.read().decode('utf-8') + + +def main(): + check_mode = '--check' in sys.argv + + remote_text = fetch_spec() + + # Validate it's valid JSON + try: + remote_json = json.loads(remote_text) + except json.JSONDecodeError as e: + print(f'Error: Downloaded spec is not valid JSON: {e}', file=sys.stderr) + sys.exit(1) + + if check_mode: + if not LOCAL_SPEC.exists(): + print(f'Error: Local spec not found at {LOCAL_SPEC}', file=sys.stderr) + sys.exit(1) + + local_json = json.loads(LOCAL_SPEC.read_text()) + + if local_json == remote_json: + print('Spec is up to date.') + sys.exit(0) + else: + print( + f'Error: Local spec ({LOCAL_SPEC}) differs from upstream.\nRun "make update-models" to update.', + file=sys.stderr, + ) + sys.exit(1) + else: + LOCAL_SPEC.parent.mkdir(parents=True, exist_ok=True) + # Write with consistent formatting + formatted = json.dumps(remote_json, indent=2, ensure_ascii=False) + '\n' + LOCAL_SPEC.write_text(formatted) + print(f'Wrote {len(formatted)} bytes to {LOCAL_SPEC}') + + +if __name__ == '__main__': + main() diff --git a/scripts/generate_models.py b/scripts/generate_models.py index 13a69b0..892458e 100644 --- a/scripts/generate_models.py +++ b/scripts/generate_models.py @@ -15,7 +15,7 @@ def main(): """Generate Pydantic models from OpenAPI spec.""" - from datamodel_code_generator import InputFileType, generate + from datamodel_code_generator import DataModelType, InputFileType, generate # Define paths spec_file = Path('specs/admin.spec.json') @@ -30,16 +30,18 @@ def main(): print(f'Generating Pydantic models from {spec_file}...') - # Generate models + # Generate models (Pydantic v2 with RootModel instead of __root__) generate( input_=spec_file, output=output_file, input_file_type=InputFileType.OpenAPI, + output_model_type=DataModelType.PydanticV2BaseModel, use_schema_description=True, use_field_description=True, field_constraints=True, use_standard_collections=True, use_annotated=True, + disable_timestamp=True, ) print(f'✅ Successfully generated models: {output_file}') diff --git a/specs/admin.spec.json b/specs/admin.spec.json index 71225af..3b3f67f 100644 --- a/specs/admin.spec.json +++ b/specs/admin.spec.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "info": { "title": "Amp Admin API", - "description": "Administration API for Amp, a high-performance ETL system for blockchain data services on The Graph.\n\n## About\n\nThe Admin API provides a RESTful HTTP interface for managing Amp's ETL operations. This API serves as the primary administrative interface for monitoring and controlling the Amp data pipeline, allowing you to deploy datasets, trigger data extraction jobs, monitor job progress, manage distributed worker locations, configure external data providers, and perform operations on Parquet files and their metadata.\n\n## Key Capabilities\n\n### Dataset Management\nHandle the lifecycle of data extraction configurations and access dataset information:\n- List all registered datasets from the metadata database registry\n- Register new dataset configurations with versioning support\n- Trigger data extraction jobs for specific datasets or dataset versions\n- Retrieve dataset details including tables and active storage locations\n\n### Job Control\nControl and monitor data extraction and processing jobs:\n- List and retrieve job information with pagination\n- Trigger extraction jobs with optional end block configuration\n- Stop running jobs gracefully\n- Delete jobs in terminal states (Completed, Stopped, Failed)\n- Bulk cleanup operations for finalized jobs\n\n### Storage Management\nManage locations where dataset tables are stored:\n- Supports local filesystem, S3, GCS, and Azure Blob Storage\n- List storage locations and their associated files\n- Delete locations with comprehensive cleanup (removes files and metadata)\n- Query file information including Parquet metadata and statistics\n\n### Provider Configuration\nConfigure external blockchain data sources:\n- Create, retrieve, and delete provider configurations\n- Support for EVM RPC endpoints and Firehose streams\n- Providers are reusable across multiple dataset definitions\n- **Security Note**: Provider configurations may contain connection details; ensure sensitive information is properly managed\n\n### Schema Analysis\nValidate SQL queries and infer output schemas:\n- Validate queries against registered datasets without execution\n- Determine output schema using DataFusion's query planner\n- Useful for building dynamic query tools and validating dataset definitions\n\n## Pagination\n\nMost list endpoints use cursor-based pagination for efficient data retrieval:\n\n### Paginated Endpoints\nThe following endpoints support pagination:\n- Jobs: `/jobs`\n- Locations: `/locations`\n- Files: `/locations/{location_id}/files`\n\n### Non-Paginated Endpoints\nThe following endpoints return all results without pagination:\n- Datasets: `/datasets` (returns all datasets)\n- Dataset Versions: `/datasets/{name}/versions` (returns all versions for a dataset)\n\n### Query Parameters (Paginated Endpoints Only)\n- `limit`: Maximum items per page (default: 50, max: 1000)\n- `last_*_id`: Cursor from previous page's `next_cursor` field\n\n### Response Format\nPaginated responses include:\n- Array of items (e.g., `jobs`, `locations`, `files`)\n- `next_cursor`: Cursor for the next page (absent when no more results)\n\n### Usage Pattern\n\n**First Page Request:**\n```\nGET /jobs?limit=100\n```\n\n**First Page Response:**\n```json\n{\n \"jobs\": [...],\n \"next_cursor\": 12345\n}\n```\n\n**Next Page Request:**\n```\nGET /jobs?limit=100&last_job_id=12345\n```\n\n**Last Page Response:**\n```json\n{\n \"jobs\": [...]\n // No next_cursor field = end of results\n}\n```\n\n### Cursor Formats\n\nEndpoints use different cursor formats based on their data type:\n\n**Integer ID Cursors (64-bit integers):**\nMost paginated endpoints use simple integer IDs as cursors:\n- Jobs: `last_job_id=12345`\n- Locations: `last_location_id=67890`\n- Files: `last_file_id=54321`\n\n## Error Handling\n\nAll error responses follow a consistent format with:\n- `error_code`: Stable, machine-readable code (SCREAMING_SNAKE_CASE)\n- `error_message`: Human-readable error description\n\nError codes are stable across API versions and suitable for programmatic error handling. Messages may change and should only be used for display or logging.\n\n## Important Notes\n\n### Dataset Registration\nSupports two main scenarios:\n- **Derived datasets** (kind=\"manifest\"): Registered in both object store and metadata database\n- **SQL datasets** (other kinds): Dataset definitions stored in object store\n\n### Job Lifecycle\nJobs have the following terminal states that allow deletion:\n- **Completed**: Job finished successfully\n- **Stopped**: Job was manually stopped\n- **Failed**: Job encountered an error\n\nNon-terminal jobs (Scheduled, Running, StopRequested, Stopping) are protected from deletion.\n\n### Storage Locations\n- Locations can be active or inactive for queries\n- Deleting a location performs comprehensive cleanup including file removal from object store\n- Each location is associated with a specific dataset table and storage URL\n", + "description": "Administration API for Amp, a high-performance ETL system for blockchain data services on The Graph.\n\n## About\n\nThe Admin API provides a RESTful HTTP interface for managing Amp's ETL operations. This API serves as the primary administrative interface for monitoring and controlling the Amp data pipeline, allowing you to deploy datasets, trigger data extraction jobs, monitor job progress, manage distributed worker locations, configure external data providers, and perform operations on Parquet files and their metadata.\n\n## Key Capabilities\n\n### Dataset Management\nHandle the lifecycle of data extraction configurations and access dataset information:\n- List all registered datasets from the metadata database registry\n- Register new dataset configurations with versioning support\n- Trigger data extraction jobs for specific datasets or dataset versions\n- Retrieve dataset details including tables and active storage locations\n\n### Job Control\nControl and monitor data extraction and processing jobs:\n- List and retrieve job information with pagination\n- Trigger extraction jobs with optional end block configuration\n- Stop running jobs gracefully\n- Delete jobs in terminal states (Completed, Stopped, Failed)\n- Bulk cleanup operations for finalized jobs\n\n### Storage Management\nManage locations where dataset tables are stored:\n- Supports local filesystem, S3, GCS, and Azure Blob Storage\n- List storage locations and their associated files\n- Delete locations with comprehensive cleanup (removes files and metadata)\n- Query file information including Parquet metadata and statistics\n\n### Provider Configuration\nConfigure external blockchain data sources:\n- Create, retrieve, and delete provider configurations\n- Support for EVM RPC endpoints and Firehose streams\n- Providers are reusable across multiple dataset definitions\n- **Security Note**: Provider configurations may contain connection details; ensure sensitive information is properly managed\n\n### Schema Analysis\nValidate SQL queries and infer output schemas:\n- Validate queries against registered datasets without execution\n- Determine output schema using DataFusion's query planner\n- Useful for building dynamic query tools and validating dataset definitions\n\n## Pagination\n\nMost list endpoints use cursor-based pagination for efficient data retrieval:\n\n### Paginated Endpoints\nThe following endpoints support pagination:\n- Jobs: `/jobs`\n\n### Non-Paginated Endpoints\nThe following endpoints return all results without pagination:\n- Datasets: `/datasets` (returns all datasets)\n- Dataset Versions: `/datasets/{name}/versions` (returns all versions for a dataset)\n\n### Query Parameters (Paginated Endpoints Only)\n- `limit`: Maximum items per page (default: 50, max: 1000)\n- `last_*_id`: Cursor from previous page's `next_cursor` field\n\n### Response Format\nPaginated responses include:\n- Array of items (e.g., `jobs`, `locations`, `files`)\n- `next_cursor`: Cursor for the next page (absent when no more results)\n\n### Usage Pattern\n\n**First Page Request:**\n```\nGET /jobs?limit=100\n```\n\n**First Page Response:**\n```json\n{\n \"jobs\": [...],\n \"next_cursor\": 12345\n}\n```\n\n**Next Page Request:**\n```\nGET /jobs?limit=100&last_job_id=12345\n```\n\n**Last Page Response:**\n```json\n{\n \"jobs\": [...]\n // No next_cursor field = end of results\n}\n```\n\n### Cursor Formats\n\nEndpoints use different cursor formats based on their data type:\n\n**Integer ID Cursors (64-bit integers):**\nMost paginated endpoints use simple integer IDs as cursors:\n- Jobs: `last_job_id=12345`\n- Locations: `last_location_id=67890`\n- Files: `last_file_id=54321`\n\n## Error Handling\n\nAll error responses follow a consistent format with:\n- `error_code`: Stable, machine-readable code (SCREAMING_SNAKE_CASE)\n- `error_message`: Human-readable error description\n\nError codes are stable across API versions and suitable for programmatic error handling. Messages may change and should only be used for display or logging.\n\n## Important Notes\n\n### Dataset Registration\nSupports two main scenarios:\n- **Derived datasets** (kind=\"manifest\"): Registered in both object store and metadata database\n- **SQL datasets** (other kinds): Dataset definitions stored in object store\n\n### Job Lifecycle\nJobs have the following terminal states that allow deletion:\n- **Completed**: Job finished successfully\n- **Stopped**: Job was manually stopped\n- **Failed**: Job encountered an error\n\nNon-terminal jobs (Scheduled, Running, StopRequested, Stopping) are protected from deletion.\n\n### Storage Locations\n- Locations can be active or inactive for queries\n- Deleting a location performs comprehensive cleanup including file removal from object store\n- Each location is associated with a specific dataset table and storage URL\n", "license": { "name": "" }, @@ -45,7 +45,7 @@ "datasets" ], "summary": "Handler for the `POST /datasets` endpoint", - "description": "Registers a new dataset configuration in the server's local registry. Accepts a JSON payload\ncontaining the dataset registration configuration.\n\n**Note**: This endpoint only registers datasets and does NOT schedule data extraction.\nTo extract data after registration, make a separate call to:\n- `POST /datasets/{namespace}/{name}/versions/dev/deploy` - for dev tag\n- `POST /datasets/{namespace}/{name}/versions/latest/deploy` - for latest tag\n- `POST /datasets/{namespace}/{name}/versions/{version}/deploy` - for specific version\n\n## Request Body\n- `dataset_name`: Name of the dataset to be registered (must be valid dataset name)\n- `version`: Optional version of the dataset to register. If omitted, only the \"dev\" tag is updated.\n- `manifest`: JSON string representation of the dataset manifest\n\n## Response\n- **201 Created**: Dataset successfully registered (or updated if version tag already exists)\n- **400 Bad Request**: Invalid dataset name, version, or manifest format\n- **500 Internal Server Error**: Database or object store error\n\n## Error Codes\n- `INVALID_PAYLOAD_FORMAT`: Request JSON is malformed or invalid\n- `INVALID_MANIFEST`: Manifest JSON parsing or structure error\n- `DEPENDENCY_VALIDATION_ERROR`: SQL queries are invalid or reference undeclared dependencies\n- `MANIFEST_REGISTRATION_ERROR`: Failed to register manifest in system\n- `MANIFEST_LINKING_ERROR`: Failed to link manifest to dataset\n- `MANIFEST_NOT_FOUND`: Manifest hash provided but manifest doesn't exist\n- `VERSION_TAGGING_ERROR`: Failed to tag the manifest with the version\n- `UNSUPPORTED_DATASET_KIND`: Dataset kind is not supported\n- `STORE_ERROR`: Failed to load or access dataset store\n\n## Behavior\nThis handler supports multiple dataset kinds for registration:\n- **Derived dataset** (kind=\"manifest\"): Registers a derived dataset manifest that transforms data from other datasets using SQL queries\n- **EVM-RPC dataset** (kind=\"evm-rpc\"): Registers a raw dataset that extracts blockchain data directly from Ethereum-compatible JSON-RPC endpoints\n- **Firehose dataset** (kind=\"firehose\"): Registers a raw dataset that streams blockchain data from StreamingFast Firehose protocol\n- **Eth Beacon dataset** (kind=\"eth-beacon\"): Registers a raw dataset that extracts Ethereum Beacon Chain data\n- **Legacy SQL datasets** are **not supported** and will return an error\n\n## Registration Process\nThe registration process involves two or three steps depending on whether a version is provided:\n1. **Register or validate manifest**: Either stores a new manifest in hash-based storage and creates\n a metadata database entry, or validates that a provided manifest hash exists in the system\n2. **Link manifest to dataset**: Links the manifest to the dataset namespace/name and automatically\n updates the \"dev\" tag to point to this manifest (performed in a transaction for atomicity)\n3. **Tag version** (optional): If a version is provided, associates the version identifier with the\n manifest hash, and updates the \"latest\" tag if this version is higher than the current latest\n\nThis approach enables:\n- Content-addressable storage by manifest hash\n- Deduplication of identical manifests\n- Separation of manifest storage, dataset linking, and version management\n- Development workflow: register without version to only update \"dev\" tag via linking\n- Release workflow: register with version to create semantic version tags and update \"latest\"\n- Reuse workflow: provide manifest hash to link existing manifest without re-registering it\n\nAll operations are idempotent:\n- **Manifest registration**: If the manifest already exists (same hash), the operation succeeds without changes\n- **Manifest linking**: If the manifest is already linked to the dataset, the operation succeeds without changes\n- **Dev tag update**: The dev tag is always updated to point to the linked manifest (last-write-wins)\n- **Version tag**: If the version tag doesn't exist, it is created; if it exists with the same hash, no changes;\n if it exists with a different hash, it is updated to point to the new hash\n- **Latest tag**: Automatically updated only if the new version is higher than the current latest version\n\nThe handler:\n- Validates dataset name and version format\n- Checks that dataset kind is supported\n- Registers/validates the manifest, links it to the dataset, and optionally tags it with a version\n- Returns appropriate status codes and error messages\n\n## Typical Workflow\nFor users wanting both registration and data extraction:\n1. `POST /datasets` - Register the dataset (this endpoint)\n2. `POST /datasets/{namespace}/{name}/versions/{version}/deploy` - Schedule data extraction", + "description": "Registers a new dataset configuration in the server's local registry. Accepts a JSON payload\ncontaining the dataset registration configuration.\n\n**Note**: This endpoint only registers datasets and does NOT schedule data extraction.\nTo extract data after registration, make a separate call to:\n- `POST /datasets/{namespace}/{name}/versions/dev/deploy` - for dev tag\n- `POST /datasets/{namespace}/{name}/versions/latest/deploy` - for latest tag\n- `POST /datasets/{namespace}/{name}/versions/{version}/deploy` - for specific version\n\n## Request Body\n- `dataset_name`: Name of the dataset to be registered (must be valid dataset name)\n- `version`: Optional version of the dataset to register. If omitted, only the \"dev\" tag is updated.\n- `manifest`: JSON string representation of the dataset manifest\n\n## Response\n- **201 Created**: Dataset successfully registered (or updated if version tag already exists)\n- **400 Bad Request**: Invalid dataset name, version, or manifest format\n- **500 Internal Server Error**: Database or object store error\n\n## Error Codes\n- `INVALID_PAYLOAD_FORMAT`: Request JSON is malformed or invalid\n- `INVALID_MANIFEST`: Manifest JSON parsing or structure error\n- `MANIFEST_VALIDATION_ERROR`: Manifest validation failed (SQL queries invalid, undeclared dependencies, etc.)\n- `MANIFEST_REGISTRATION_ERROR`: Failed to register manifest in system\n- `MANIFEST_LINKING_ERROR`: Failed to link manifest to dataset\n- `MANIFEST_NOT_FOUND`: Manifest hash provided but manifest doesn't exist\n- `VERSION_TAGGING_ERROR`: Failed to tag the manifest with the version\n\n## Behavior\nThis handler supports multiple dataset kinds for registration:\n- **Derived dataset** (kind=\"manifest\"): Registers a derived dataset manifest that transforms data from other datasets using SQL queries\n- **EVM-RPC dataset** (kind=\"evm-rpc\"): Registers a raw dataset that extracts blockchain data directly from Ethereum-compatible JSON-RPC endpoints\n- **Firehose dataset** (kind=\"firehose\"): Registers a raw dataset that streams blockchain data from StreamingFast Firehose protocol\n- **Legacy SQL datasets** are **not supported** and will return an error\n\n## Registration Process\nThe registration process involves two or three steps depending on whether a version is provided:\n1. **Register or validate manifest**: Either stores a new manifest in hash-based storage and creates\n a metadata database entry, or validates that a provided manifest hash exists in the system\n2. **Link manifest to dataset**: Links the manifest to the dataset namespace/name and automatically\n updates the \"dev\" tag to point to this manifest (performed in a transaction for atomicity)\n3. **Tag version** (optional): If a version is provided, associates the version identifier with the\n manifest hash, and updates the \"latest\" tag if this version is higher than the current latest\n\nThis approach enables:\n- Content-addressable storage by manifest hash\n- Deduplication of identical manifests\n- Separation of manifest storage, dataset linking, and version management\n- Development workflow: register without version to only update \"dev\" tag via linking\n- Release workflow: register with version to create semantic version tags and update \"latest\"\n- Reuse workflow: provide manifest hash to link existing manifest without re-registering it\n\nAll operations are idempotent:\n- **Manifest registration**: If the manifest already exists (same hash), the operation succeeds without changes\n- **Manifest linking**: If the manifest is already linked to the dataset, the operation succeeds without changes\n- **Dev tag update**: The dev tag is always updated to point to the linked manifest (last-write-wins)\n- **Version tag**: If the version tag doesn't exist, it is created; if it exists with the same hash, no changes;\n if it exists with a different hash, it is updated to point to the new hash\n- **Latest tag**: Automatically updated only if the new version is higher than the current latest version\n\nThe handler:\n- Validates dataset name and version format\n- Checks that dataset kind is supported\n- Registers/validates the manifest, links it to the dataset, and optionally tags it with a version\n- Returns appropriate status codes and error messages\n\n## Typical Workflow\nFor users wanting both registration and data extraction:\n1. `POST /datasets` - Register the dataset (this endpoint)\n2. `POST /datasets/{namespace}/{name}/versions/{version}/deploy` - Schedule data extraction", "operationId": "datasets_register", "requestBody": { "content": { @@ -59,7 +59,14 @@ }, "responses": { "201": { - "description": "Dataset successfully registered or updated" + "description": "Dataset successfully registered or updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterResponse" + } + } + } }, "400": { "description": "Invalid request format or manifest", @@ -90,7 +97,7 @@ "datasets" ], "summary": "Handler for the `DELETE /datasets/{namespace}/{name}` endpoint", - "description": "Removes all manifest links and version tags for a dataset.\n\n## Response\n- **204 No Content**: Dataset successfully deleted (or didn't exist)\n- **400 Bad Request**: Invalid path parameters\n- **500 Internal Server Error**: Database operation error\n\n## Error Codes\n- `INVALID_PATH`: Invalid namespace or name in path parameters\n- `UNLINK_DATASET_MANIFESTS_ERROR`: Failed to unlink dataset manifests from dataset store\n\n## Behavior\nThis endpoint deletes all metadata for a dataset including:\n- All manifest links in the dataset_manifests table\n- All version tags (cascaded automatically via foreign key constraint)\n- Orphaned manifest files (manifests not referenced by any other dataset)\n\nThis operation is fully idempotent - it returns 204 even if the dataset\ndoesn't exist. Manifests that are still referenced by other datasets are\npreserved.", + "description": "Removes all manifest links and version tags for a dataset.\n\n## Path Parameters\n- `namespace`: Dataset namespace\n- `name`: Dataset name\n\n## Response\n- **204 No Content**: Dataset successfully deleted (or didn't exist)\n- **400 Bad Request**: Invalid path parameters\n- **500 Internal Server Error**: Database operation error\n\n## Error Codes\n- `INVALID_PATH`: Invalid namespace or name in path parameters\n- `UNLINK_DATASET_MANIFESTS_ERROR`: Failed to unlink dataset manifests from dataset store\n\n## Behavior\nThis endpoint deletes all metadata for a dataset including:\n- All manifest links in the dataset_manifests table\n- All version tags (cascaded automatically via foreign key constraint)\n- Orphaned manifest files (manifests not referenced by any other dataset)\n\nThis operation is fully idempotent - it returns 204 even if the dataset\ndoesn't exist. Manifests that are still referenced by other datasets are\npreserved.", "operationId": "delete_dataset", "parameters": [ { @@ -145,7 +152,7 @@ "datasets" ], "summary": "Handler for the `GET /datasets/{namespace}/{name}/versions` endpoint", - "description": "Returns all versions for a dataset with their metadata.\n\n## Response\n- **200 OK**: Successfully retrieved version list\n- **400 Bad Request**: Invalid path parameters\n- **500 Internal Server Error**: Database query error\n\n## Error Codes\n- `INVALID_PATH`: Invalid namespace or name in path parameters\n- `LIST_VERSION_TAGS_ERROR`: Failed to list version tags from dataset store\n- `RESOLVE_REVISION_ERROR`: Failed to resolve dev tag revision\n\n## Behavior\nThis endpoint returns comprehensive version information for a dataset:\n- All semantic versions sorted in descending order (newest first)\n- For each version: manifest hash, creation time, and last update time\n- Special tags: \"latest\" (if any semantic versions exist) and \"dev\" (if set)\n\nThe \"latest\" tag is automatically managed and always points to the highest\nsemantic version. The \"dev\" tag is explicitly managed via the registration\nendpoint and may point to any manifest hash.\n\nReturns an empty list if the dataset has no registered versions.", + "description": "Returns all versions for a dataset with their metadata.\n\n## Path Parameters\n- `namespace`: Dataset namespace\n- `name`: Dataset name\n\n## Response\n- **200 OK**: Successfully retrieved version list\n- **400 Bad Request**: Invalid path parameters\n- **500 Internal Server Error**: Database query error\n\n## Error Codes\n- `INVALID_PATH`: Invalid namespace or name in path parameters\n- `LIST_VERSION_TAGS_ERROR`: Failed to list version tags from dataset store\n- `RESOLVE_REVISION_ERROR`: Failed to resolve dev tag revision\n\n## Behavior\nThis endpoint returns comprehensive version information for a dataset:\n- All semantic versions sorted in descending order (newest first)\n- For each version: manifest hash, creation time, and last update time\n- Special tags: \"latest\" (if any semantic versions exist) and \"dev\" (if set)\n\nThe \"latest\" tag is automatically managed and always points to the highest\nsemantic version. The \"dev\" tag is explicitly managed via the registration\nendpoint and may point to any manifest hash.\n\nReturns an empty list if the dataset has no registered versions.", "operationId": "list_dataset_versions", "parameters": [ { @@ -207,7 +214,7 @@ "datasets" ], "summary": "Handler for the `GET /datasets/{namespace}/{name}/versions/{revision}` endpoint", - "description": "Returns detailed dataset information for the specified revision.\n\n## Response\n- **200 OK**: Successfully retrieved dataset information\n- **400 Bad Request**: Invalid path parameters\n- **404 Not Found**: Dataset or revision not found\n- **500 Internal Server Error**: Database or dataset store error\n\n## Error Codes\n- `INVALID_PATH`: Invalid namespace, name, or revision in path parameters\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n- `GET_MANIFEST_PATH_ERROR`: Failed to query manifest path from metadata database\n- `READ_MANIFEST_ERROR`: Failed to read manifest file from object store\n- `PARSE_MANIFEST_ERROR`: Failed to parse manifest JSON\n\n## Behavior\nThis endpoint retrieves detailed information about a specific dataset revision.\nThe revision parameter supports four types:\n- Semantic version (e.g., \"1.2.3\")\n- Manifest hash (SHA256 hash)\n- \"latest\" - resolves to the highest semantic version\n- \"dev\" - resolves to the development version\n\nThe endpoint first resolves the revision to a manifest hash, then returns\nbasic dataset information including namespace, name, revision, manifest hash, and kind.", + "description": "Returns detailed dataset information for the specified revision.\n\n## Path Parameters\n- `namespace`: Dataset namespace\n- `name`: Dataset name\n- `revision`: Revision (version, hash, \"latest\", or \"dev\")\n\n## Response\n- **200 OK**: Successfully retrieved dataset information\n- **400 Bad Request**: Invalid path parameters\n- **404 Not Found**: Dataset or revision not found\n- **500 Internal Server Error**: Database or dataset store error\n\n## Error Codes\n- `INVALID_PATH`: Invalid namespace, name, or revision in path parameters\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n- `GET_DATASET_ERROR`: Failed to get dataset from dataset store\n\n## Behavior\nThis endpoint retrieves detailed information about a specific dataset revision.\nThe revision parameter supports four types:\n- Semantic version (e.g., \"1.2.3\")\n- Manifest hash (SHA256 hash)\n- \"latest\" - resolves to the highest semantic version\n- \"dev\" - resolves to the development version\n\nThe endpoint first resolves the revision to a manifest hash, then returns\ndataset information including namespace, name, revision, manifest hash, kind,\nstart block, finalized blocks setting, and table names.", "operationId": "get_dataset_by_revision", "parameters": [ { @@ -288,7 +295,7 @@ "datasets" ], "summary": "Handler for the `POST /datasets/{namespace}/{name}/versions/{revision}/deploy` endpoint", - "description": "Schedules a data extraction job for the specified dataset revision.\n\n## Response\n- **202 Accepted**: Job successfully scheduled\n- **400 Bad Request**: Invalid path parameters or request body\n- **404 Not Found**: Dataset or revision not found\n- **500 Internal Server Error**: Database or scheduler error\n\n## Error Codes\n- `INVALID_PATH`: Invalid path parameters (namespace, name, or revision)\n- `INVALID_BODY`: Invalid request body (malformed JSON or missing required fields)\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `LIST_VERSION_TAGS_ERROR`: Failed to list version tags from dataset store\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n- `GET_DATASET_ERROR`: Failed to load dataset from store\n- `SCHEDULER_ERROR`: Failed to schedule extraction job\n\n## Behavior\nThis endpoint schedules a data extraction job for a dataset:\n1. Resolves the revision to find the corresponding version tag\n2. Loads the full dataset configuration from the dataset store\n3. Schedules an extraction job with the specified parameters\n4. Returns job ID for tracking\n\nThe revision parameter supports four types:\n- Semantic version (e.g., \"1.2.3\") - uses that specific version\n- \"latest\" - resolves to the highest semantic version\n- \"dev\" - resolves to the development version tag\n- Manifest hash (SHA256 hash) - finds the version that points to this hash\n\nJobs are executed asynchronously by worker nodes. Use the returned job ID\nto track progress via the jobs endpoints.", + "description": "Schedules a data extraction job for the specified dataset revision.\n\n## Path Parameters\n- `namespace`: Dataset namespace\n- `name`: Dataset name\n- `revision`: Revision (version, hash, \"latest\", or \"dev\")\n\n## Request Body\n- `end_block`: End block configuration (null for continuous, \"latest\", number, or negative offset)\n- `parallelism`: Number of parallel workers (default: 1, only for raw datasets)\n- `worker_id`: Optional worker selector (exact ID or glob pattern)\n- `verify`: Enable cryptographic verification of EVM block data (default: false)\n- `retry_strategy`: Optional retry strategy controlling how failed jobs are retried\n\n## Response\n- **202 Accepted**: Job successfully scheduled\n- **400 Bad Request**: Invalid path parameters or request body\n- **404 Not Found**: Dataset or revision not found\n- **500 Internal Server Error**: Database or scheduler error\n\n## Error Codes\n- `INVALID_PATH`: Invalid path parameters (namespace, name, or revision)\n- `INVALID_BODY`: Invalid request body (malformed JSON or missing required fields)\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `LIST_VERSION_TAGS_ERROR`: Failed to list version tags from dataset store\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n- `GET_DATASET_ERROR`: Failed to load dataset from store\n- `WORKER_NOT_AVAILABLE`: Specified worker not found or inactive\n- `SCHEDULER_ERROR`: Failed to schedule extraction job\n\n## Behavior\nThis endpoint schedules a data extraction job for a dataset:\n1. Resolves the revision to find the corresponding version tag\n2. Loads the full dataset configuration from the dataset store\n3. Schedules an extraction job with the specified parameters\n4. Returns job ID for tracking\n\nThe revision parameter supports four types:\n- Semantic version (e.g., \"1.2.3\") - uses that specific version\n- \"latest\" - resolves to the highest semantic version\n- \"dev\" - resolves to the development version tag\n- Manifest hash (SHA256 hash) - finds the version that points to this hash\n\nJobs are executed asynchronously by worker nodes. Use the returned job ID\nto track progress via the jobs endpoints.", "operationId": "deploy_dataset", "parameters": [ { @@ -373,14 +380,14 @@ } } }, - "/datasets/{namespace}/{name}/versions/{revision}/manifest": { + "/datasets/{namespace}/{name}/versions/{revision}/jobs": { "get": { "tags": [ "datasets" ], - "summary": "Handler for the `GET /datasets/{namespace}/{name}/versions/{revision}/manifest` endpoint", - "description": "Retrieves the raw manifest JSON for the specified dataset revision.\n\n## Response\n- **200 OK**: Successfully retrieved manifest\n- **404 Not Found**: Dataset, revision, or manifest not found\n- **500 Internal Server Error**: Database or object store error\n\n## Error Codes\n- `INVALID_PATH`: Invalid namespace, name, or revision in path parameters\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `MANIFEST_NOT_FOUND`: The manifest file was not found in object storage\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n- `GET_MANIFEST_PATH_ERROR`: Failed to query manifest path from metadata database\n- `READ_MANIFEST_ERROR`: Failed to read manifest file from object store\n- `PARSE_MANIFEST_ERROR`: Failed to parse manifest JSON\n\n## Behavior\nThis endpoint returns the raw manifest JSON document for a dataset revision.\nThe revision parameter supports four types:\n- Semantic version (e.g., \"1.2.3\")\n- Manifest hash (SHA256 hash)\n- \"latest\" - resolves to the highest semantic version\n- \"dev\" - resolves to the development version\n\nThe endpoint first resolves the revision to a manifest hash, then retrieves\nthe manifest JSON from object storage. Manifests are immutable and\ncontent-addressable, identified by their SHA256 hash.", - "operationId": "get_dataset_manifest", + "summary": "Handler for the `GET /datasets/{namespace}/{name}/versions/{revision}/jobs` endpoint", + "description": "Retrieves and returns all jobs for a specific dataset revision.\n\n## Path Parameters\n- `namespace`: Dataset namespace\n- `name`: Dataset name\n- `revision`: Dataset revision (version, hash, \"latest\", or \"dev\")\n\n## Response\n- **200 OK**: Returns all jobs for the dataset\n- **400 Bad Request**: Invalid path parameters\n- **404 Not Found**: Dataset or revision not found\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_PATH`: Invalid path parameters (namespace, name, or revision malformed)\n- `DATASET_NOT_FOUND`: Dataset revision does not exist\n- `RESOLVE_REVISION_ERROR`: Failed to resolve dataset revision (database error)\n- `LIST_JOBS_ERROR`: Failed to list jobs from metadata database (database error)\n- `LIST_JOB_DESCRIPTORS_ERROR`: Failed to list job descriptors from metadata database\n\nThis handler:\n- Validates and extracts the dataset reference from the URL path\n- Resolves the revision to a manifest hash using the dataset store\n- Queries all jobs filtered by the manifest hash\n- Returns all matching jobs", + "operationId": "list_dataset_jobs", "parameters": [ { "name": "namespace", @@ -412,11 +419,21 @@ ], "responses": { "200": { - "description": "Successfully retrieved manifest", + "description": "Successfully retrieved jobs", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Value" + "$ref": "#/components/schemas/JobsResponse" + } + } + } + }, + "400": { + "description": "Invalid path parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" } } } @@ -444,14 +461,14 @@ } } }, - "/datasets/{namespace}/{name}/versions/{version}": { - "delete": { + "/datasets/{namespace}/{name}/versions/{revision}/manifest": { + "get": { "tags": [ "datasets" ], - "summary": "Handler for the `DELETE /datasets/{namespace}/{name}/versions/{version}` endpoint", - "description": "Removes a semantic version tag from a dataset.\n\n## Response\n- **204 No Content**: Version successfully deleted (or didn't exist)\n- **400 Bad Request**: Invalid path parameters or attempting to delete the \"latest\" version\n- **500 Internal Server Error**: Database operation error\n\n## Error Codes\n- `INVALID_PATH`: Invalid namespace, name, or version in path parameters\n- `CANNOT_DELETE_LATEST_VERSION`: Cannot delete the version currently tagged as \"latest\"\n- `RESOLVE_LATEST_REVISION_ERROR`: Failed to resolve the \"latest\" tag to its manifest hash\n- `RESOLVE_VERSION_REVISION_ERROR`: Failed to resolve the requested version to its manifest hash\n- `DELETE_VERSION_TAG_ERROR`: Failed to delete version tag from dataset store\n\n## Behavior\nThis endpoint removes a semantic version tag from a dataset. The deletion follows this flow:\n\n1. **Check version existence**: Resolves the requested version to its manifest hash.\n If the version doesn't exist, returns 204 immediately (idempotent).\n\n2. **Check \"latest\" protection**: Resolves the \"latest\" tag to its manifest hash and compares\n with the requested version's hash. If they point to the same manifest, deletion is rejected\n with a 400 error. You must create a newer version first to update the \"latest\" tag.\n\n3. **Delete version tag**: Removes only the version tag from the database. The underlying\n manifest file is never deleted (manifests are content-addressable and may be referenced\n by other versions or datasets).\n\nThis operation is fully idempotent - it returns 204 even if the version doesn't exist.", - "operationId": "delete_dataset_version", + "summary": "Handler for the `GET /datasets/{namespace}/{name}/versions/{revision}/manifest` endpoint", + "description": "Retrieves the raw manifest JSON for the specified dataset revision.\n\n## Path Parameters\n- `namespace`: Dataset namespace\n- `name`: Dataset name\n- `revision`: Revision (version, hash, \"latest\", or \"dev\")\n\n## Response\n- **200 OK**: Successfully retrieved manifest\n- **404 Not Found**: Dataset, revision, or manifest not found\n- **500 Internal Server Error**: Database or object store error\n\n## Error Codes\n- `INVALID_PATH`: Invalid namespace, name, or revision in path parameters\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `MANIFEST_NOT_FOUND`: The manifest file was not found in object storage\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n- `GET_MANIFEST_PATH_ERROR`: Failed to query manifest path from metadata database\n- `READ_MANIFEST_ERROR`: Failed to read manifest file from object store\n- `PARSE_MANIFEST_ERROR`: Failed to parse manifest JSON\n\n## Behavior\nThis endpoint returns the raw manifest JSON document for a dataset revision.\nThe revision parameter supports four types:\n- Semantic version (e.g., \"1.2.3\")\n- Manifest hash (SHA256 hash)\n- \"latest\" - resolves to the highest semantic version\n- \"dev\" - resolves to the development version\n\nThe endpoint first resolves the revision to a manifest hash, then retrieves\nthe manifest JSON from object storage. Manifests are immutable and\ncontent-addressable, identified by their SHA256 hash.", + "operationId": "get_dataset_manifest", "parameters": [ { "name": "namespace", @@ -472,9 +489,9 @@ } }, { - "name": "version", + "name": "revision", "in": "path", - "description": "Semantic version (e.g., 1.2.3)", + "description": "Revision (version, hash, latest, or dev)", "required": true, "schema": { "type": "string" @@ -482,11 +499,18 @@ } ], "responses": { - "204": { - "description": "Version successfully deleted" + "200": { + "description": "Successfully retrieved manifest", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Value" + } + } + } }, - "400": { - "description": "Invalid path parameters", + "404": { + "description": "Dataset or revision not found", "content": { "application/json": { "schema": { @@ -508,39 +532,56 @@ } } }, - "/files/{file_id}": { - "get": { + "/datasets/{namespace}/{name}/versions/{revision}/restore": { + "post": { "tags": [ - "files" + "datasets" ], - "summary": "Handler for the `GET /files/{file_id}` endpoint", - "description": "Retrieves and returns a specific file by its ID from the metadata database.\n\n## Path Parameters\n- `file_id`: The unique identifier of the file to retrieve (must be a positive integer)\n\n## Response\n- **200 OK**: Returns the file information as JSON\n- **400 Bad Request**: Invalid file ID format (not a number, zero, or negative)\n- **404 Not Found**: File with the given ID does not exist\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_FILE_ID`: The provided ID is not a valid positive integer\n- `FILE_NOT_FOUND`: No file exists with the given ID\n- `METADATA_DB_ERROR`: Internal database error occurred\n\nThis handler:\n- Validates and extracts the file ID from the URL path\n- Queries the metadata database for the file with location information\n- Returns appropriate HTTP status codes and error messages", - "operationId": "files_get", + "summary": "Handler for the `POST /datasets/{namespace}/{name}/versions/{revision}/restore` endpoint", + "description": "Restores physical table locations from object storage into the metadata database.\n\n## Path Parameters\n- `namespace`: Dataset namespace\n- `name`: Dataset name\n- `revision`: Revision (version, hash, latest, or dev)\n\n## Response\n- **202 Accepted**: Physical tables successfully restored from storage\n- **400 Bad Request**: Invalid path parameters\n- **404 Not Found**: Dataset or revision not found, or no tables found in storage\n- **500 Internal Server Error**: Database or storage error\n\n## Error Codes\n- `INVALID_PATH`: Invalid path parameters (namespace, name, or revision)\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n- `GET_DATASET_ERROR`: Failed to load dataset from store\n- `RESTORE_TABLE_REVISION_ERROR`: Failed to restore a table from storage\n- `REGISTER_FILES_ERROR`: Failed to register files for a table\n- `TABLE_NOT_FOUND`: Table data not found in object storage\n- `TASK_JOIN_ERROR`: Failed to join a restoration task\n\n## Behavior\nThis endpoint restores dataset physical tables from object storage:\n1. Resolves the revision to find the corresponding dataset\n2. Scans object storage for existing physical table files\n3. Re-indexes all Parquet file metadata from storage\n4. Registers the physical table locations in the metadata database\n5. Marks the restored locations as active\n\nThis is useful for:\n- Recovering from metadata database loss\n- Setting up a new system with pre-existing data\n- Re-syncing metadata after storage restoration", + "operationId": "restore_dataset", "parameters": [ { - "name": "file_id", + "name": "namespace", "in": "path", - "description": "File ID", + "description": "Dataset namespace", "required": true, "schema": { - "type": "integer", - "format": "int64" + "type": "string" + } + }, + { + "name": "name", + "in": "path", + "description": "Dataset name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "revision", + "in": "path", + "description": "Revision (version, hash, latest, or dev)", + "required": true, + "schema": { + "type": "string" } } ], "responses": { - "200": { - "description": "Successfully retrieved file information", + "202": { + "description": "Physical tables successfully restored", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/FileInfo" + "$ref": "#/components/schemas/RestoreResponse" } } } }, "400": { - "description": "Invalid file ID", + "description": "Bad request (invalid parameters)", "content": { "application/json": { "schema": { @@ -550,7 +591,7 @@ } }, "404": { - "description": "File not found", + "description": "Dataset or revision not found", "content": { "application/json": { "schema": { @@ -572,48 +613,84 @@ } } }, - "/jobs": { - "get": { + "/datasets/{namespace}/{name}/versions/{revision}/tables/{table_name}/restore": { + "post": { "tags": [ - "jobs" + "datasets" ], - "summary": "Handler for the `GET /jobs` endpoint", - "description": "Retrieves and returns a paginated list of jobs from the metadata database.\n\n## Query Parameters\n- `limit`: Maximum number of jobs to return (default: 50, max: 1000)\n- `last_job_id`: ID of the last job from previous page for cursor-based pagination\n\n## Response\n- **200 OK**: Returns paginated job data with next cursor\n- **400 Bad Request**: Invalid limit parameter (0, negative, or > 1000)\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_QUERY_PARAMETERS`: Invalid query parameters (malformed or unparseable)\n- `LIMIT_TOO_LARGE`: Limit exceeds maximum allowed value (>1000)\n- `LIMIT_INVALID`: Limit is zero\n- `LIST_JOBS_ERROR`: Failed to list jobs from scheduler (database error)", - "operationId": "jobs_list", + "summary": "Handler for the `POST /datasets/{namespace}/{name}/versions/{revision}/tables/{table_name}/restore` endpoint", + "description": "Restores a single physical table, either by activating a known revision or\nby discovering the latest revision from object storage.\n\n## Path Parameters\n- `namespace`: Dataset namespace\n- `name`: Dataset name\n- `revision`: Revision (version, hash, latest, or dev)\n- `table_name`: Table name\n\n## Request Body (optional JSON)\n- `location_id` (optional, i64): If provided, activates this existing revision\n for the table. If omitted, discovers the latest revision from object storage\n via UUID heuristic.\n\n## Response\n- **200 OK**: Table successfully restored\n- **400 Bad Request**: Invalid path parameters or request body\n- **404 Not Found**: Dataset, revision, or table not found\n- **500 Internal Server Error**: Database or storage error\n\n## Error Codes\n- `INVALID_PATH`: Invalid path parameters (namespace, name, revision, or table_name)\n- `INVALID_BODY`: Invalid request body\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n- `GET_DATASET_ERROR`: Failed to load dataset from store\n- `TABLE_NOT_IN_MANIFEST`: Table not found in the dataset manifest\n- `TABLE_NOT_FOUND`: Table data not found in object storage\n- `GET_REVISION_ERROR`: Failed to look up revision by location ID\n- `REVISION_NOT_FOUND`: No revision exists for the given location ID\n- `REGISTER_AND_ACTIVATE_ERROR`: Failed to register and activate physical table\n- `RESTORE_TABLE_REVISION_ERROR`: Failed to restore a table from storage\n- `REGISTER_FILES_ERROR`: Failed to register files for a table\n\n## Behavior\n\n**With `location_id`:**\n1. Resolves the revision and loads the dataset\n2. Validates the table exists in the dataset manifest\n3. Upserts the `physical_tables` entry\n4. Marks all existing revisions for the table as inactive\n5. Marks the specified `location_id` as active\n\n**Without `location_id`:**\n1. Resolves the revision and loads the dataset\n2. Validates the table exists in the dataset manifest\n3. Scans object storage for the latest revision (by UUID ordering)\n4. Registers and activates the discovered revision\n5. Re-indexes all Parquet file metadata from storage\n\nThis is useful for:\n- Recovering from metadata database loss\n- Activating a specific known revision for a table\n- Setting up a new system with pre-existing data\n- Re-syncing metadata after storage restoration", + "operationId": "restore_table", "parameters": [ { - "name": "limit", - "in": "query", - "description": "Maximum number of jobs to return (default: 50, max: 1000)", - "required": false, + "name": "namespace", + "in": "path", + "description": "Dataset namespace", + "required": true, "schema": { - "type": "integer", - "minimum": 0 + "type": "string" } }, { - "name": "last_job_id", - "in": "query", - "description": "ID of the last job from the previous page for pagination", - "required": false, + "name": "name", + "in": "path", + "description": "Dataset name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "revision", + "in": "path", + "description": "Revision (version, hash, latest, or dev)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "table_name", + "in": "path", + "description": "Table name", + "required": true, "schema": { "type": "string" } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/RestoreTablePayload" + } + ] + } + } + } + }, "responses": { "200": { - "description": "Successfully retrieved jobs", + "description": "Table successfully restored" + }, + "400": { + "description": "Bad request (invalid parameters)", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/JobsResponse" + "$ref": "#/components/schemas/ErrorResponse" } } } }, - "400": { - "description": "Invalid query parameters", + "404": { + "description": "Dataset, revision, or table not found", "content": { "application/json": { "schema": { @@ -633,31 +710,51 @@ } } } - }, + } + }, + "/datasets/{namespace}/{name}/versions/{version}": { "delete": { "tags": [ - "jobs" + "datasets" ], - "summary": "Handler for the `DELETE /jobs?status=` endpoint", - "description": "Deletes jobs based on status filter. Supports deleting jobs by various status criteria.\n\n## Query Parameters\n- `status=terminal`: Delete all jobs in terminal states (Completed, Stopped, Failed)\n- `status=completed`: Delete all completed jobs\n- `status=stopped`: Delete all stopped jobs\n- `status=error`: Delete all failed jobs\n\n## Response\n- **204 No Content**: Operation completed successfully\n- **400 Bad Request**: Invalid or missing status query parameter\n- **500 Internal Server Error**: Database error occurred\n\n## Error Codes\n- `INVALID_QUERY_PARAM`: Invalid or missing status parameter\n- `DELETE_JOBS_BY_STATUS_ERROR`: Failed to delete jobs by status from scheduler (database error)\n\n## Behavior\nThis handler provides bulk job cleanup with the following characteristics:\n- Only jobs in terminal states (Completed, Stopped, Failed) are deleted\n- Non-terminal jobs are completely protected from deletion\n- Database layer ensures atomic bulk deletion\n- Safe to call even when no terminal jobs exist\n\n## Terminal States\nJobs are deleted when in these states:\n- Completed → Safe to delete\n- Stopped → Safe to delete\n- Failed → Safe to delete\n\nProtected states (never deleted):\n- Scheduled → Job is waiting to run\n- Running → Job is actively executing\n- StopRequested → Job is being stopped\n- Stopping → Job is in process of stopping\n- Unknown → Invalid state\n\n## Usage\nThis endpoint is typically used for:\n- Periodic cleanup of completed jobs\n- Administrative maintenance\n- Freeing up database storage", - "operationId": "jobs_delete_many", + "summary": "Handler for the `DELETE /datasets/{namespace}/{name}/versions/{version}` endpoint", + "description": "Removes a semantic version tag from a dataset.\n\n## Path Parameters\n- `namespace`: Dataset namespace\n- `name`: Dataset name\n- `version`: Semantic version to delete (e.g., \"1.2.3\")\n\n## Response\n- **204 No Content**: Version successfully deleted (or didn't exist)\n- **400 Bad Request**: Invalid path parameters or attempting to delete the \"latest\" version\n- **500 Internal Server Error**: Database operation error\n\n## Error Codes\n- `INVALID_PATH`: Invalid namespace, name, or version in path parameters\n- `CANNOT_DELETE_LATEST_VERSION`: Cannot delete the version currently tagged as \"latest\"\n- `RESOLVE_LATEST_REVISION_ERROR`: Failed to resolve the \"latest\" tag to its manifest hash\n- `RESOLVE_VERSION_REVISION_ERROR`: Failed to resolve the requested version to its manifest hash\n- `DELETE_VERSION_TAG_ERROR`: Failed to delete version tag from dataset store\n\n## Behavior\nThis endpoint removes a semantic version tag from a dataset. The deletion follows this flow:\n\n1. **Check version existence**: Resolves the requested version to its manifest hash.\n If the version doesn't exist, returns 204 immediately (idempotent).\n\n2. **Check \"latest\" protection**: Resolves the \"latest\" tag to its manifest hash and compares\n with the requested version's hash. If they point to the same manifest, deletion is rejected\n with a 400 error. You must create a newer version first to update the \"latest\" tag.\n\n3. **Delete version tag**: Removes only the version tag from the database. The underlying\n manifest file is never deleted (manifests are content-addressable and may be referenced\n by other versions or datasets).\n\nThis operation is fully idempotent - it returns 204 even if the version doesn't exist.", + "operationId": "delete_dataset_version", "parameters": [ { - "name": "status", - "in": "query", - "description": "Status filter for jobs to delete", + "name": "namespace", + "in": "path", + "description": "Dataset namespace", "required": true, "schema": { - "$ref": "#/components/schemas/String" + "type": "string" + } + }, + { + "name": "name", + "in": "path", + "description": "Dataset name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "version", + "in": "path", + "description": "Semantic version (e.g., 1.2.3)", + "required": true, + "schema": { + "type": "string" } } ], "responses": { "204": { - "description": "Jobs deleted successfully" + "description": "Version successfully deleted" }, "400": { - "description": "Invalid query parameters", + "description": "Invalid path parameters", "content": { "application/json": { "schema": { @@ -679,38 +776,39 @@ } } }, - "/jobs/{id}": { + "/files/{file_id}": { "get": { "tags": [ - "jobs" + "files" ], - "summary": "Handler for the `GET /jobs/{id}` endpoint", - "description": "Retrieves and returns a specific job by its ID from the metadata database.\n\n## Path Parameters\n- `id`: The unique identifier of the job to retrieve (must be a valid JobId)\n\n## Response\n- **200 OK**: Returns the job information as JSON\n- **400 Bad Request**: Invalid job ID format (not parseable as JobId)\n- **404 Not Found**: Job with the given ID does not exist\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_JOB_ID`: The provided ID is not a valid job identifier\n- `JOB_NOT_FOUND`: No job exists with the given ID\n- `GET_JOB_ERROR`: Failed to retrieve job from scheduler (database error)", - "operationId": "jobs_get", + "summary": "Handler for the `GET /files/{file_id}` endpoint", + "description": "Retrieves and returns a specific file by its ID from the metadata database.\n\n## Path Parameters\n- `file_id`: The unique identifier of the file to retrieve (must be a positive integer)\n\n## Response\n- **200 OK**: Returns the file information as JSON\n- **400 Bad Request**: Invalid file ID format (not a number, zero, or negative)\n- **404 Not Found**: File with the given ID does not exist\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_FILE_ID`: The provided ID is not a valid positive integer\n- `FILE_NOT_FOUND`: No file exists with the given ID\n- `METADATA_DB_ERROR`: Internal database error occurred\n\nThis handler:\n- Validates and extracts the file ID from the URL path\n- Queries the metadata database for the file with location information\n- Returns appropriate HTTP status codes and error messages", + "operationId": "files_get", "parameters": [ { - "name": "id", + "name": "file_id", "in": "path", - "description": "Job ID", + "description": "File ID", "required": true, "schema": { - "type": "string" + "type": "integer", + "format": "int64" } } ], "responses": { "200": { - "description": "Successfully retrieved job information", + "description": "Successfully retrieved file information", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/JobInfo" + "$ref": "#/components/schemas/FileInfo" } } } }, "400": { - "description": "Invalid job ID", + "description": "Invalid file ID", "content": { "application/json": { "schema": { @@ -720,7 +818,7 @@ } }, "404": { - "description": "Job not found", + "description": "File not found", "content": { "application/json": { "schema": { @@ -740,42 +838,59 @@ } } } - }, - "delete": { + } + }, + "/jobs": { + "get": { "tags": [ "jobs" ], - "summary": "Handler for the `DELETE /jobs/{id}` endpoint", - "description": "Deletes a job by its ID if it's in a terminal state (Completed, Stopped, or Failed).\nThis is a safe, idempotent operation that only removes finalized jobs from the system.\n\n## Path Parameters\n- `id`: The unique identifier of the job to delete (must be a valid JobId)\n\n## Response\n- **204 No Content**: Job was successfully deleted or does not exist (idempotent)\n- **400 Bad Request**: Invalid job ID format (not parseable as JobId)\n- **409 Conflict**: Job exists but is not in a terminal state (cannot be deleted)\n- **500 Internal Server Error**: Database error occurred\n\n## Error Codes\n- `INVALID_JOB_ID`: The provided ID is not a valid job identifier\n- `JOB_CONFLICT`: Job exists but is not in a terminal state\n- `GET_JOB_ERROR`: Failed to retrieve job from scheduler (database error)\n- `DELETE_JOB_ERROR`: Failed to delete job from scheduler (database error)\n\n## Idempotent Behavior\nThis handler is idempotent - deleting a non-existent job returns 204 (success).\nThis allows clients to safely retry deletions without worrying about 404 errors.\n\n## Behavior\nThis handler provides safe job deletion with the following characteristics:\n- Only jobs in terminal states (Completed, Stopped, Failed) can be deleted\n- Non-terminal jobs are protected from accidental deletion\n- Non-existent jobs return success (idempotent behavior)\n- Database layer ensures atomic deletion\n\n## Terminal States\nJobs can only be deleted when in these states:\n- Completed → Safe to delete\n- Stopped → Safe to delete\n- Failed → Safe to delete\n\nProtected states (cannot be deleted):\n- Scheduled → Job is waiting to run\n- Running → Job is actively executing\n- StopRequested → Job is being stopped\n- Stopping → Job is in process of stopping\n- Unknown → Invalid state", - "operationId": "jobs_delete", + "summary": "Handler for the `GET /jobs` endpoint", + "description": "Retrieves and returns a paginated list of jobs from the metadata database.\n\n## Query Parameters\n- `limit`: Maximum number of jobs to return (default: 50, max: 1000)\n- `last_job_id`: ID of the last job from previous page for cursor-based pagination\n- `status`: Status filter - \"active\" (default, shows non-terminal jobs), \"all\" (shows all jobs), or comma-separated status values (e.g., \"scheduled,running\")\n\n## Response\n- **200 OK**: Returns paginated job data with next cursor\n- **400 Bad Request**: Invalid limit parameter (0, negative, or > 1000)\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_QUERY_PARAMETERS`: Invalid query parameters (malformed or unparseable)\n- `LIMIT_TOO_LARGE`: Limit exceeds maximum allowed value (>1000)\n- `LIMIT_INVALID`: Limit is zero\n- `LIST_JOBS_ERROR`: Failed to list jobs from scheduler (database error)\n- `LIST_JOB_DESCRIPTORS_ERROR`: Failed to list job descriptors from metadata database", + "operationId": "jobs_list", "parameters": [ { - "name": "id", - "in": "path", - "description": "Job ID", - "required": true, + "name": "limit", + "in": "query", + "description": "Maximum number of jobs to return (default: 50, max: 1000)", + "required": false, "schema": { "type": "integer", - "format": "int64" + "minimum": 0 } - } - ], - "responses": { - "204": { - "description": "Job deleted successfully or does not exist (idempotent)" }, - "400": { - "description": "Invalid job ID", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } + { + "name": "last_job_id", + "in": "query", + "description": "ID of the last job from the previous page for pagination", + "required": false, + "schema": { + "type": "string" } }, - "409": { - "description": "Job cannot be deleted (not in terminal state)", + { + "name": "status", + "in": "query", + "description": "Status filter: 'active' (default, non-terminal jobs), 'all' (all jobs), or comma-separated status values", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved jobs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobsResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters", "content": { "application/json": { "schema": { @@ -795,34 +910,37 @@ } } } - } - }, - "/jobs/{id}/stop": { - "put": { + }, + "post": { "tags": [ "jobs" ], - "summary": "Handler for the `PUT /jobs/{id}/stop` endpoint", - "description": "Stops a running job using the specified job ID. This is an idempotent\noperation that handles job termination requests safely.\n\n## Path Parameters\n- `id`: The unique identifier of the job to stop (must be a valid JobId)\n\n## Response\n- **200 OK**: Job stop request processed successfully, or job already in terminal state (idempotent)\n- **400 Bad Request**: Invalid job ID format (not parseable as JobId)\n- **404 Not Found**: Job with the given ID does not exist\n- **500 Internal Server Error**: Database connection or scheduler error\n\n## Error Codes\n- `INVALID_JOB_ID`: The provided ID is not a valid job identifier\n- `JOB_NOT_FOUND`: No job exists with the given ID\n- `STOP_JOB_ERROR`: Database error during stop operation execution\n- `UNEXPECTED_STATE_CONFLICT`: Internal state machine error (indicates a bug)\n\n## Idempotent Behavior\nThis handler is idempotent - stopping a job that's already in a terminal state returns success (200).\nThis allows clients to safely retry stop requests without worrying about conflict errors.\n\nThe desired outcome of a stop request is that the job is not running. If the job is already\nstopped, completed, or failed, this outcome is achieved, so we return success.\n\n## Behavior\nThis handler provides idempotent job stopping with the following characteristics:\n- Jobs already in terminal states (Stopped, Completed, Failed) return success (idempotent)\n- Only running/scheduled jobs transition to stop-requested state\n- Job lookup and stop request are performed atomically within a single transaction\n- Database layer validates state transitions and prevents race conditions\n\n## State Transitions\nValid stop transitions:\n- Scheduled → StopRequested (200 OK)\n- Running → StopRequested (200 OK)\n\nAlready terminal (idempotent - return success):\n- Stopped → no change (200 OK)\n- Completed → no change (200 OK)\n- Failed → no change (200 OK)\n\nThe handler:\n- Validates and extracts the job ID from the URL path\n- Delegates to scheduler for atomic stop operation (job lookup + stop + worker notification)\n- Returns success if job is already in terminal state (idempotent)\n- Returns appropriate HTTP status codes and error messages", - "operationId": "jobs_stop", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Job ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" + "summary": "Handler for the `POST /jobs` endpoint", + "description": "Schedules a new job for execution by an available worker. The job type is\ndetermined by the `kind` field in the request body (`gc`, `materialize-raw`,\nor `materialize-derived`). Additional fields depend on the job kind and are\ndefined by the corresponding job descriptor type.\n\n## Request Body\n- `kind`: Job type (`gc`, `materialize-raw`, or `materialize-derived`)\n- `worker_id`: Optional worker selector (exact ID or glob pattern)\n- `retry_strategy`: Optional retry strategy controlling how failed jobs are retried\n- Additional fields vary by job kind (see [`CreateJobRequest`] variants)\n\n## Response\n- **202 Accepted**: Job scheduled successfully\n- **400 Bad Request**: Invalid request body, invalid retry strategy, or no workers\n- **409 Conflict**: An active job with the same idempotency key already exists\n- **500 Internal Server Error**: Scheduler error\n\n## Error Codes\n- `INVALID_BODY`: The request body is not valid JSON, has missing/invalid fields, or has invalid retry strategy parameters\n- `NO_WORKERS_AVAILABLE`: No active workers to handle the job\n- `ACTIVE_JOB_CONFLICT`: An active job with the same idempotency key already exists\n- `SCHEDULER_ERROR`: Internal scheduler failure", + "operationId": "jobs_create", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateJobRequest" + } } - } - ], + }, + "required": true + }, "responses": { - "200": { - "description": "Job stop request processed successfully, or job already in terminal state (idempotent)" + "202": { + "description": "Job scheduled successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateJobResponse" + } + } + } }, "400": { - "description": "Invalid job ID", + "description": "Bad request (invalid body or no workers)", "content": { "application/json": { "schema": { @@ -831,8 +949,8 @@ } } }, - "404": { - "description": "Job not found", + "409": { + "description": "Active job conflict", "content": { "application/json": { "schema": { @@ -852,47 +970,28 @@ } } } - } - }, - "/locations": { - "get": { + }, + "delete": { "tags": [ - "locations" + "jobs" ], - "summary": "Handler for the `GET /locations` endpoint", - "description": "Retrieves and returns a paginated list of locations from the metadata database.\n\n## Query Parameters\n- `limit`: Maximum number of locations to return (default: 50, max: 1000)\n- `last_location_id`: ID of the last location from previous page for cursor-based pagination\n\n## Response\n- **200 OK**: Returns paginated location data with next cursor\n- **400 Bad Request**: Invalid limit parameter (0, negative, or > 1000)\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_REQUEST`: Invalid query parameters (limit out of range)\n- `METADATA_DB_ERROR`: Internal database error occurred\n\nThis handler:\n- Accepts query parameters for pagination (limit, last_location_id)\n- Validates the limit parameter (max 1000)\n- Calls the metadata DB to list locations with pagination\n- Returns a structured response with locations and next cursor", - "operationId": "locations_list", + "summary": "Handler for the `DELETE /jobs?status=` endpoint", + "description": "Deletes jobs based on status filter. Supports deleting jobs by various status criteria.\n\n## Query Parameters\n- `status=terminal`: Delete all jobs in terminal states (Completed, Stopped, Failed)\n- `status=completed`: Delete all completed jobs\n- `status=stopped`: Delete all stopped jobs\n- `status=error`: Delete all failed jobs\n\n## Response\n- **204 No Content**: Operation completed successfully\n- **400 Bad Request**: Invalid or missing status query parameter\n- **500 Internal Server Error**: Database error occurred\n\n## Error Codes\n- `INVALID_QUERY_PARAM`: Invalid or missing status parameter\n- `DELETE_JOBS_BY_STATUS_ERROR`: Failed to delete jobs by status from scheduler (database error)\n\n## Behavior\nThis handler provides bulk job cleanup with the following characteristics:\n- Only jobs in terminal states (Completed, Stopped, Failed) are deleted\n- Non-terminal jobs are completely protected from deletion\n- Database layer ensures atomic bulk deletion\n- Safe to call even when no terminal jobs exist\n\n## Terminal States\nJobs are deleted when in these states:\n- Completed → Safe to delete\n- Stopped → Safe to delete\n- Failed → Safe to delete\n\nProtected states (never deleted):\n- Scheduled → Job is waiting to run\n- Running → Job is actively executing\n- StopRequested → Job is being stopped\n- Stopping → Job is in process of stopping\n- Unknown → Invalid state\n\n## Usage\nThis endpoint is typically used for:\n- Periodic cleanup of completed jobs\n- Administrative maintenance\n- Freeing up database storage", + "operationId": "jobs_delete_many", "parameters": [ { - "name": "limit", - "in": "query", - "description": "Maximum number of locations to return (default: 50, max: 1000)", - "required": false, - "schema": { - "type": "integer", - "minimum": 0 - } - }, - { - "name": "last_location_id", + "name": "status", "in": "query", - "description": "ID of the last location from the previous page for pagination", - "required": false, + "description": "Status filter for jobs to delete", + "required": true, "schema": { - "type": "string" + "$ref": "#/components/schemas/String" } } ], "responses": { - "200": { - "description": "Successfully retrieved locations", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LocationsResponse" - } - } - } + "204": { + "description": "Jobs deleted successfully" }, "400": { "description": "Invalid query parameters", @@ -917,39 +1016,38 @@ } } }, - "/locations/{id}": { + "/jobs/{id}": { "get": { "tags": [ - "locations" + "jobs" ], - "summary": "Handler for the `GET /locations/{id}` endpoint", - "description": "Retrieves and returns a specific location by its ID from the metadata database.\n\n## Path Parameters\n- `id`: The unique identifier of the location to retrieve (must be a positive integer)\n\n## Response\n- **200 OK**: Returns the location information as JSON\n- **400 Bad Request**: Invalid location ID format (not a number, zero, or negative)\n- **404 Not Found**: Location with the given ID does not exist\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_LOCATION_ID`: The provided ID is not a valid positive integer\n- `LOCATION_NOT_FOUND`: No location exists with the given ID\n- `METADATA_DB_ERROR`: Internal database error occurred\n\nThis handler:\n- Validates and extracts the location ID from the URL path\n- Queries the metadata database for the location\n- Returns appropriate HTTP status codes and error messages", - "operationId": "locations_get", + "summary": "Handler for the `GET /jobs/{id}` endpoint", + "description": "Retrieves and returns a specific job by its ID from the metadata database.\n\n## Path Parameters\n- `id`: The unique identifier of the job to retrieve (must be a valid JobId)\n\n## Response\n- **200 OK**: Returns the job information as JSON\n- **400 Bad Request**: Invalid job ID format (not parseable as JobId)\n- **404 Not Found**: Job with the given ID does not exist\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_JOB_ID`: The provided ID is not a valid job identifier\n- `JOB_NOT_FOUND`: No job exists with the given ID\n- `GET_JOB_ERROR`: Failed to retrieve job from scheduler (database error)\n- `GET_DESCRIPTOR_ERROR`: Failed to retrieve job descriptor from metadata database", + "operationId": "jobs_get", "parameters": [ { "name": "id", "in": "path", - "description": "Location ID", + "description": "Job ID", "required": true, "schema": { - "type": "integer", - "format": "int64" + "type": "string" } } ], "responses": { "200": { - "description": "Successfully retrieved location information", + "description": "Successfully retrieved job information", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/LocationInfoWithDetails" + "$ref": "#/components/schemas/JobInfo" } } } }, "400": { - "description": "Invalid location ID", + "description": "Invalid job ID", "content": { "application/json": { "schema": { @@ -959,7 +1057,7 @@ } }, "404": { - "description": "Location not found", + "description": "Job not found", "content": { "application/json": { "schema": { @@ -982,48 +1080,29 @@ }, "delete": { "tags": [ - "locations" + "jobs" ], - "summary": "Handler for the `DELETE /locations/{id}` endpoint", - "description": "Deletes a specific location by its ID from the metadata database.\n\n## Path Parameters\n- `id`: The unique identifier of the location to delete (must be a positive integer)\n\n## Query Parameters\n- `force`: (optional, default: false) Force deletion even if location is active\n\n## Response\n- **204 No Content**: Location successfully deleted\n- **400 Bad Request**: Invalid location ID format or invalid query parameters\n- **404 Not Found**: Location with the given ID does not exist\n- **409 Conflict**: Location is active (without force=true) or has an ongoing job\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_LOCATION_ID`: The provided ID is not a valid positive integer\n- `INVALID_QUERY_PARAMETERS`: The query parameters cannot be parsed\n- `LOCATION_NOT_FOUND`: No location exists with the given ID\n- `ACTIVE_LOCATION_CONFLICT`: Location is active and cannot be deleted without force=true\n- `ONGOING_JOB_CONFLICT`: Location has an ongoing job and cannot be deleted\n- `METADATA_DB_ERROR`: Internal database error occurred\n\n## Safety Checks\n- Active locations require `force=true` to be deleted\n- Locations with ongoing jobs cannot be deleted (even with force=true)\n- Users must stop active jobs before deleting associated locations\n\nThis handler:\n- Validates and extracts the location ID from the URL path\n- Validates optional query parameters (force flag)\n- Performs safety checks for active locations and ongoing jobs\n- Deletes associated files from object store\n- Deletes the location from the metadata database\n- Returns appropriate HTTP status codes and error messages", - "operationId": "locations_delete", + "summary": "Handler for the `DELETE /jobs/{id}` endpoint", + "description": "Deletes a job by its ID if it's in a terminal state (Completed, Stopped, or Failed).\nThis is a safe, idempotent operation that only removes finalized jobs from the system.\n\n## Path Parameters\n- `id`: The unique identifier of the job to delete (must be a valid JobId)\n\n## Response\n- **204 No Content**: Job was successfully deleted or does not exist (idempotent)\n- **400 Bad Request**: Invalid job ID format (not parseable as JobId)\n- **409 Conflict**: Job exists but is not in a terminal state (cannot be deleted)\n- **500 Internal Server Error**: Database error occurred\n\n## Error Codes\n- `INVALID_JOB_ID`: The provided ID is not a valid job identifier\n- `JOB_CONFLICT`: Job exists but is not in a terminal state\n- `GET_JOB_ERROR`: Failed to retrieve job from scheduler (database error)\n- `DELETE_JOB_ERROR`: Failed to delete job from scheduler (database error)\n\n## Idempotent Behavior\nThis handler is idempotent - deleting a non-existent job returns 204 (success).\nThis allows clients to safely retry deletions without worrying about 404 errors.\n\n## Behavior\nThis handler provides safe job deletion with the following characteristics:\n- Only jobs in terminal states (Completed, Stopped, Failed) can be deleted\n- Non-terminal jobs are protected from accidental deletion\n- Non-existent jobs return success (idempotent behavior)\n- Database layer ensures atomic deletion\n\n## Terminal States\nJobs can only be deleted when in these states:\n- Completed → Safe to delete\n- Stopped → Safe to delete\n- Failed → Safe to delete\n\nProtected states (cannot be deleted):\n- Scheduled → Job is waiting to run\n- Running → Job is actively executing\n- StopRequested → Job is being stopped\n- Stopping → Job is in process of stopping\n- Unknown → Invalid state", + "operationId": "jobs_delete", "parameters": [ { "name": "id", "in": "path", - "description": "Location ID", + "description": "Job ID", "required": true, "schema": { "type": "integer", "format": "int64" } - }, - { - "name": "force", - "in": "query", - "description": "Force deletion even if location is active", - "required": false, - "schema": { - "type": "boolean" - } } ], "responses": { "204": { - "description": "Location successfully deleted" + "description": "Job deleted successfully or does not exist (idempotent)" }, "400": { - "description": "Invalid location ID or query parameters", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "Location not found", + "description": "Invalid job ID", "content": { "application/json": { "schema": { @@ -1033,7 +1112,7 @@ } }, "409": { - "description": "Location is active or has ongoing job", + "description": "Job cannot be deleted (not in terminal state)", "content": { "application/json": { "schema": { @@ -1055,39 +1134,48 @@ } } }, - "/locations/{location_id}/files": { + "/jobs/{id}/events": { "get": { "tags": [ - "locations" + "jobs" ], - "summary": "Handler for the `GET /locations/{location_id}/files` endpoint", - "description": "Retrieves and returns a paginated list of files for a specific location from the metadata database.\n\n## Path Parameters\n- `location_id`: The unique identifier of the location (must be a positive integer)\n\n## Query Parameters\n- `limit`: Maximum number of files to return (default: 50, max: 1000)\n- `last_file_id`: ID of the last file from previous page for cursor-based pagination\n\n## Response\n- **200 OK**: Returns paginated file data with next cursor\n- **400 Bad Request**: Invalid location ID format or invalid limit parameter\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_LOCATION_ID`: Invalid location ID format\n- `INVALID_QUERY_PARAMETERS`: Invalid query parameters (limit out of range)\n- `LIMIT_TOO_LARGE`: Limit exceeds maximum allowed value\n- `LIMIT_INVALID`: Limit is zero or negative\n- `METADATA_DB_ERROR`: Internal database error occurred\n\nThis handler:\n- Validates and extracts the location ID from the URL path\n- Accepts query parameters for pagination (limit, last_file_id)\n- Validates the limit parameter (max 1000)\n- Calls the metadata DB to list files with pagination for the specified location\n- Returns a structured response with minimal file info and next cursor", - "operationId": "locations_list_files", + "summary": "Handler for the `GET /jobs/{id}/events` endpoint", + "description": "Retrieves all lifecycle events for a specific job from the event log.\n\n## Path Parameters\n- `id`: The unique identifier of the job\n\n## Response\n- **200 OK**: Returns all events for the job\n- **400 Bad Request**: Invalid job ID format\n- **404 Not Found**: Job with the given ID does not exist\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_JOB_ID`: The provided ID is not a valid job identifier\n- `JOB_NOT_FOUND`: No job exists with the given ID\n- `GET_JOB_ERROR`: Failed to retrieve job from scheduler\n- `GET_JOB_EVENTS_ERROR`: Failed to retrieve job events from the database", + "operationId": "get_job_events", "parameters": [ { - "name": "location_id", + "name": "id", "in": "path", - "description": "Location ID", + "description": "Job ID", "required": true, "schema": { - "type": "integer", - "format": "int64" + "type": "string" } } ], "responses": { "200": { - "description": "Successfully retrieved location files", + "description": "Successfully retrieved job events", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/LocationFilesResponse" + "$ref": "#/components/schemas/JobEventsResponse" } } } }, "400": { - "description": "Invalid location ID or query parameters", + "description": "Invalid job ID", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Job not found", "content": { "application/json": { "schema": { @@ -1109,35 +1197,47 @@ } } }, - "/manifests": { - "post": { + "/jobs/{id}/events/{event_id}": { + "get": { "tags": [ - "manifests" + "jobs" ], - "summary": "Handler for the `POST /manifests` endpoint", - "description": "Registers a new manifest in content-addressable storage without linking to any dataset or creating version tags.\nThis endpoint is useful for pre-registering manifests before associating them with specific datasets.\n\n## Request Body\nThe request body should contain a complete manifest JSON object. The manifest kind determines\nthe validation rules:\n- `kind=\"manifest\"` (Derived): Validates SQL dependencies\n- `kind=\"evm-rpc\"`, `kind=\"firehose\"`, `kind=\"eth-beacon\"` (Raw): Validates structure only\n\n## Response\n- **201 Created**: Manifest successfully registered, returns the computed hash\n- **400 Bad Request**: Invalid JSON format, unsupported kind, or validation failure\n- **500 Internal Server Error**: Manifest store error\n\n## Error Codes\n- `INVALID_PAYLOAD_FORMAT`: Request JSON is malformed or invalid\n- `INVALID_MANIFEST`: Manifest JSON parsing or structure error\n- `DEPENDENCY_VALIDATION_ERROR`: SQL dependency validation failed (derived datasets only)\n- `UNSUPPORTED_DATASET_KIND`: Dataset kind is not supported\n- `MANIFEST_STORE_ERROR`: Failed to store manifest in object store or metadata database\n\n## Registration Process\nUnlike `POST /datasets`, this endpoint performs minimal registration:\n1. **Parse and validate**: Validates manifest structure and dependencies (for derived datasets)\n2. **Canonicalize**: Re-serializes manifest to canonical JSON format\n3. **Compute hash**: Generates content hash from canonical JSON\n4. **Store manifest**: Writes to object store and registers in metadata database\n\nThis handler:\n- Validates and extracts the manifest JSON from the request body\n- Parses and validates based on dataset kind\n- Stores the manifest in content-addressable storage\n- Returns the computed manifest hash", - "operationId": "manifests_register", - "requestBody": { - "content": { - "application/json": { - "schema": {} + "summary": "Handler for the `GET /jobs/{id}/events/{event_id}` endpoint", + "description": "Retrieves the full details of a single lifecycle event for a job, including\nthe optional detail payload (e.g., job descriptor for SCHEDULED events).\n\n## Path Parameters\n- `id`: The unique identifier of the job\n- `event_id`: The unique identifier of the event\n\n## Response\n- **200 OK**: Returns the full event details\n- **400 Bad Request**: Invalid job ID or event ID format\n- **404 Not Found**: Job or event not found\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_JOB_ID`: The provided job ID or event ID is not valid\n- `JOB_NOT_FOUND`: No job exists with the given ID\n- `EVENT_NOT_FOUND`: No event exists with the given ID for the specified job\n- `GET_JOB_ERROR`: Failed to retrieve job from scheduler\n- `GET_JOB_EVENT_ERROR`: Failed to retrieve job event from the database\n\nThis handler:\n- Validates and extracts the job ID and event ID from the URL path\n- Verifies the job exists in the scheduler\n- Queries the event by ID for the specified job\n- Returns the full event details including the optional detail payload", + "operationId": "get_job_event_by_id", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Job ID", + "required": true, + "schema": { + "type": "string" } }, - "required": true - }, + { + "name": "event_id", + "in": "path", + "description": "Event ID", + "required": true, + "schema": { + "type": "string" + } + } + ], "responses": { - "201": { - "description": "Manifest successfully registered", + "200": { + "description": "Successfully retrieved job event", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RegisterManifestResponse" + "$ref": "#/components/schemas/JobEventDetailResponse" } } } }, "400": { - "description": "Invalid request format or manifest", + "description": "Invalid job ID or event ID", "content": { "application/json": { "schema": { @@ -1146,8 +1246,8 @@ } } }, - "500": { - "description": "Internal server error", + "404": { + "description": "Job or event not found", "content": { "application/json": { "schema": { @@ -1155,26 +1255,6 @@ } } } - } - } - }, - "delete": { - "tags": [ - "manifests" - ], - "summary": "Handler for the `DELETE /manifests` endpoint", - "description": "Deletes all orphaned manifests (manifests with no dataset links).\nThis is a bulk cleanup operation for removing unused manifests and reclaiming storage space.\n\n## Response\n- **200 OK**: Returns JSON with count of deleted manifests\n- **500 Internal Server Error**: Database error\n\n## Error Codes\n- `LIST_ORPHANED_MANIFESTS_ERROR`: Failed to list orphaned manifests\n\n## Pruning Process\nThis handler:\n1. Queries the metadata database for all manifests not linked to any datasets\n2. Deletes each orphaned manifest concurrently from both object store and metadata database\n3. Logs individual deletion failures but continues processing remaining manifests\n4. Returns the count of successfully deleted manifests\n\nIndividual manifest deletion failures are logged as warnings but don't fail the entire operation,\nallowing partial cleanup even if some manifests cannot be removed.\nThe operation is idempotent - safe to call repeatedly.", - "operationId": "manifests_prune", - "responses": { - "200": { - "description": "Orphaned manifests pruned successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PruneResponse" - } - } - } }, "500": { "description": "Internal server error", @@ -1189,19 +1269,19 @@ } } }, - "/manifests/{hash}": { + "/jobs/{id}/progress": { "get": { "tags": [ - "manifests" + "jobs" ], - "summary": "Handler for the `GET /manifests/{hash}` endpoint", - "description": "Retrieves the raw manifest JSON for a specific manifest hash.\n\n## Path Parameters\n- `hash`: Manifest content hash (validated hash format)\n\n## Response\n- **200 OK**: Returns the raw manifest JSON\n- **400 Bad Request**: Invalid manifest hash format\n- **404 Not Found**: Manifest with the given hash does not exist\n- **500 Internal Server Error**: Manifest retrieval error\n\n## Error Codes\n- `INVALID_HASH`: The provided hash is not valid (invalid hash format or parsing error)\n- `MANIFEST_NOT_FOUND`: No manifest exists with the given hash\n- `MANIFEST_RETRIEVAL_ERROR`: Failed to retrieve manifest from the dataset manifests store\n\n## Retrieval Process\nThis handler retrieves manifests from content-addressable storage:\n- The dataset manifests store queries the metadata database internally to resolve the hash to a file path\n- Then fetches the manifest content from the object store\n\nThis handler:\n- Validates and extracts the manifest hash from the URL path\n- Retrieves the raw manifest JSON from the dataset manifests store using the hash\n- Returns the manifest as a JSON response with proper Content-Type header", - "operationId": "manifests_get_by_hash", + "summary": "Handler for the `GET /jobs/{id}/progress` endpoint", + "description": "Retrieves progress information for all tables written by a specific job,\nincluding current block numbers, file counts, and size statistics.\n\n## Path Parameters\n- `id`: The unique identifier of the job\n\n## Response\n- **200 OK**: Returns progress for all tables written by this job\n- **400 Bad Request**: Invalid job ID format\n- **404 Not Found**: Job with the given ID does not exist\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_JOB_ID`: The provided ID is not a valid job identifier\n- `JOB_NOT_FOUND`: No job exists with the given ID\n- `GET_JOB_ERROR`: Failed to retrieve job from scheduler\n- `GET_TABLES_ERROR`: Failed to get tables written by this job\n- `GET_DATASET_ERROR`: Failed to get dataset definition\n- `GET_ACTIVE_REVISION_ERROR`: Failed to get active physical table revision\n- `SNAPSHOT_TABLE_ERROR`: Failed to snapshot physical table\n- `MULTI_NETWORK_SEGMENTS_ERROR`: Table contains multi-network segments; synced range\n cannot be computed. This indicates a catalog inconsistency — the state is\n distinguishable from \"no data synced yet\" (which returns 200 with null block fields).\n- `BLOCK_NUMBER_OVERFLOW`: A block number in the synced range cannot be represented as\n i64. This indicates data-integrity corruption; the block number is reported in the\n error response rather than silently rewritten to 0.", + "operationId": "get_job_progress", "parameters": [ { - "name": "hash", + "name": "id", "in": "path", - "description": "Manifest content hash", + "description": "Job ID", "required": true, "schema": { "type": "string" @@ -1210,17 +1290,17 @@ ], "responses": { "200": { - "description": "Successfully retrieved manifest JSON (schema varies by manifest kind)", + "description": "Successfully retrieved job progress", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ManifestResponse" + "$ref": "#/components/schemas/JobProgressResponse" } } } }, "400": { - "description": "Invalid manifest hash", + "description": "Invalid job ID", "content": { "application/json": { "schema": { @@ -1230,7 +1310,7 @@ } }, "404": { - "description": "Manifest not found", + "description": "Job not found", "content": { "application/json": { "schema": { @@ -1240,7 +1320,7 @@ } }, "500": { - "description": "Manifest retrieval error", + "description": "Internal server error", "content": { "application/json": { "schema": { @@ -1250,31 +1330,34 @@ } } } - }, - "delete": { + } + }, + "/jobs/{id}/stop": { + "put": { "tags": [ - "manifests" + "jobs" ], - "summary": "Handler for the `DELETE /manifests/{hash}` endpoint", - "description": "Deletes a manifest from both object store and metadata database.\n**Manifests linked to datasets cannot be deleted** (returns 409 Conflict).\n\nThis endpoint is idempotent: deleting a non-existent manifest returns success (204 No Content).\n\n## Path Parameters\n- `hash`: Manifest content hash to delete\n\n## Response\n- **204 No Content**: Manifest successfully deleted (or already deleted)\n- **400 Bad Request**: Invalid manifest hash format\n- **409 Conflict**: Manifest is linked to datasets and cannot be deleted\n- **500 Internal Server Error**: Store or database error\n\n## Error Codes\n- `INVALID_HASH`: Invalid hash format\n- `MANIFEST_LINKED`: Manifest is linked to datasets and cannot be deleted\n- `MANIFEST_DELETE_ERROR`: Failed to delete manifest\n\n## Deletion Flow\nThis handler:\n1. Validates and extracts the manifest hash from the URL path\n2. Checks if the manifest is linked to any datasets\n3. If linked: Returns 409 Conflict error (deletion not allowed)\n4. If not linked:\n - Deletes manifest record from metadata database\n - Deletes manifest file from object store\n - Treats \"not found\" as success (idempotent behavior)\n5. Returns 204 No Content on success\n\n## Safety Notes\n- Only unlinked manifests can be deleted (no dataset dependencies)\n- To delete a linked manifest, first remove all dataset associations\n- Deletion is permanent and cannot be undone", - "operationId": "manifests_delete", + "summary": "Handler for the `PUT /jobs/{id}/stop` endpoint", + "description": "Stops a running job using the specified job ID. This is an idempotent\noperation that handles job termination requests safely.\n\n## Path Parameters\n- `id`: The unique identifier of the job to stop (must be a valid JobId)\n\n## Response\n- **200 OK**: Job stop request processed successfully, or job already in terminal state (idempotent)\n- **400 Bad Request**: Invalid job ID format (not parseable as JobId)\n- **404 Not Found**: Job with the given ID does not exist\n- **500 Internal Server Error**: Database connection or scheduler error\n\n## Error Codes\n- `INVALID_JOB_ID`: The provided ID is not a valid job identifier\n- `JOB_NOT_FOUND`: No job exists with the given ID\n- `STOP_JOB_ERROR`: Database error during stop operation execution\n- `UNEXPECTED_STATE_CONFLICT`: Internal state machine error (indicates a bug)\n\n## Idempotent Behavior\nThis handler is idempotent - stopping a job that's already in a terminal state returns success (200).\nThis allows clients to safely retry stop requests without worrying about conflict errors.\n\nThe desired outcome of a stop request is that the job is not running. If the job is already\nstopped, completed, or failed, this outcome is achieved, so we return success.\n\n## Behavior\nThis handler provides idempotent job stopping with the following characteristics:\n- Jobs already in terminal states (Stopped, Completed, Failed) return success (idempotent)\n- Only running/scheduled jobs transition to stop-requested state\n- Job lookup and stop request are performed atomically within a single transaction\n- Database layer validates state transitions and prevents race conditions\n\n## State Transitions\nValid stop transitions:\n- Scheduled → StopRequested (200 OK)\n- Running → StopRequested (200 OK)\n\nAlready terminal (idempotent - return success):\n- Stopped → no change (200 OK)\n- Completed → no change (200 OK)\n- Failed → no change (200 OK)\n\nThe handler:\n- Validates and extracts the job ID from the URL path\n- Delegates to scheduler for atomic stop operation (job lookup + stop + worker notification)\n- Returns success if job is already in terminal state (idempotent)\n- Returns appropriate HTTP status codes and error messages", + "operationId": "jobs_stop", "parameters": [ { - "name": "hash", + "name": "id", "in": "path", - "description": "Manifest content hash", + "description": "Job ID", "required": true, "schema": { - "type": "string" + "type": "integer", + "format": "int64" } } ], "responses": { - "204": { - "description": "Manifest successfully deleted (or already deleted)" + "200": { + "description": "Job stop request processed successfully, or job already in terminal state (idempotent)" }, "400": { - "description": "Invalid hash", + "description": "Invalid job ID", "content": { "application/json": { "schema": { @@ -1283,8 +1366,8 @@ } } }, - "409": { - "description": "Manifest linked to datasets", + "404": { + "description": "Job not found", "content": { "application/json": { "schema": { @@ -1306,7 +1389,234 @@ } } }, - "/manifests/{hash}/datasets": { + "/manifests": { + "get": { + "tags": [ + "manifests" + ], + "summary": "Handler for the `GET /manifests` endpoint", + "description": "Returns all registered manifests in the system.\n\n## Response\n- **200 OK**: Successfully retrieved all manifests\n- **500 Internal Server Error**: Database query error\n\n## Error Codes\n- `LIST_ALL_MANIFESTS_ERROR`: Failed to list all manifests from metadata database\n\n## Behavior\nThis handler returns a comprehensive list of all manifests registered in the system.\nFor each manifest, it includes:\n- The content-addressable hash (SHA-256)\n- The dataset kind (e.g., \"evm-rpc\", \"solana\", \"firehose\", \"manifest\")\n- The number of datasets using this manifest\n\nResults are ordered by hash (lexicographical).", + "operationId": "list_all_manifests", + "responses": { + "200": { + "description": "Successfully retrieved all manifests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ManifestsResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "manifests" + ], + "summary": "Handler for the `POST /manifests` endpoint", + "description": "Registers a new manifest in content-addressable storage without linking to any dataset or creating version tags.\nThis endpoint is useful for pre-registering manifests before associating them with specific datasets.\n\n## Request Body\nThe request body should contain a complete manifest JSON object. The manifest kind determines\nthe validation rules:\n- `kind=\"manifest\"` (Derived): Validates SQL dependencies\n- `kind=\"evm-rpc\"`, `kind=\"firehose\"`, `kind=\"solana\"` (Raw): Validates structure only\n\n## Response\n- **201 Created**: Manifest successfully registered, returns the computed hash\n- **400 Bad Request**: Invalid JSON format, unsupported kind, or validation failure\n- **500 Internal Server Error**: Manifest store error\n\n## Error Codes\n- `INVALID_PAYLOAD_FORMAT`: Request JSON is malformed or invalid\n- `INVALID_MANIFEST`: Manifest JSON parsing or structure error\n- `MANIFEST_VALIDATION_ERROR`: Manifest validation failed (derived datasets only)\n- `MANIFEST_STORAGE_ERROR`: Failed to store manifest in object store\n- `MANIFEST_REGISTRATION_ERROR`: Failed to register manifest in metadata database\n\n## Registration Process\nUnlike `POST /datasets`, this endpoint performs minimal registration:\n1. **Parse and validate**: Validates manifest structure and dependencies (for derived datasets)\n2. **Canonicalize**: Re-serializes manifest to canonical JSON format\n3. **Compute hash**: Generates content hash from canonical JSON\n4. **Store manifest**: Writes to object store and registers in metadata database\n\nThis handler:\n- Validates and extracts the manifest JSON from the request body\n- Parses and validates based on dataset kind\n- Stores the manifest in content-addressable storage\n- Returns the computed manifest hash", + "operationId": "manifests_register", + "requestBody": { + "content": { + "application/json": { + "schema": {} + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Manifest successfully registered", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterManifestResponse" + } + } + } + }, + "400": { + "description": "Invalid request format or manifest", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "manifests" + ], + "summary": "Handler for the `DELETE /manifests` endpoint", + "description": "Deletes all orphaned manifests (manifests with no dataset links).\nThis is a bulk cleanup operation for removing unused manifests and reclaiming storage space.\n\n## Response\n- **200 OK**: Returns JSON with count of deleted manifests\n- **500 Internal Server Error**: Database error\n\n## Error Codes\n- `LIST_ORPHANED_MANIFESTS_ERROR`: Failed to list orphaned manifests\n\n## Pruning Process\nThis handler:\n1. Queries the metadata database for all manifests not linked to any datasets\n2. Deletes each orphaned manifest concurrently from both object store and metadata database\n3. Logs individual deletion failures but continues processing remaining manifests\n4. Returns the count of successfully deleted manifests\n\nIndividual manifest deletion failures are logged as warnings but don't fail the entire operation,\nallowing partial cleanup even if some manifests cannot be removed.\nThe operation is idempotent - safe to call repeatedly.", + "operationId": "manifests_prune", + "responses": { + "200": { + "description": "Orphaned manifests pruned successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PruneResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/manifests/{hash}": { + "get": { + "tags": [ + "manifests" + ], + "summary": "Handler for the `GET /manifests/{hash}` endpoint", + "description": "Retrieves the raw manifest JSON for a specific manifest hash.\n\n## Path Parameters\n- `hash`: Manifest content hash (validated hash format)\n\n## Response\n- **200 OK**: Returns the raw manifest JSON\n- **400 Bad Request**: Invalid manifest hash format\n- **404 Not Found**: Manifest with the given hash does not exist\n- **500 Internal Server Error**: Manifest retrieval error\n\n## Error Codes\n- `INVALID_HASH`: The provided hash is not valid (invalid hash format or parsing error)\n- `MANIFEST_NOT_FOUND`: No manifest exists with the given hash\n- `MANIFEST_METADATA_DB_ERROR`: Failed to query manifest path from metadata database\n- `MANIFEST_OBJECT_STORE_ERROR`: Failed to retrieve manifest from object store\n\n## Retrieval Process\nThis handler retrieves manifests from content-addressable storage:\n- The dataset manifests store queries the metadata database internally to resolve the hash to a file path\n- Then fetches the manifest content from the object store\n\nThis handler:\n- Validates and extracts the manifest hash from the URL path\n- Retrieves the raw manifest JSON from the dataset manifests store using the hash\n- Returns the manifest as a JSON response with proper Content-Type header", + "operationId": "manifests_get_by_hash", + "parameters": [ + { + "name": "hash", + "in": "path", + "description": "Manifest content hash", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved manifest JSON (schema varies by manifest kind)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ManifestResponse" + } + } + } + }, + "400": { + "description": "Invalid manifest hash", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Manifest not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Manifest retrieval error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "manifests" + ], + "summary": "Handler for the `DELETE /manifests/{hash}` endpoint", + "description": "Deletes a manifest from both object store and metadata database.\n**Manifests linked to datasets cannot be deleted** (returns 409 Conflict).\n\nThis endpoint is idempotent: deleting a non-existent manifest returns success (204 No Content).\n\n## Path Parameters\n- `hash`: Manifest content hash to delete\n\n## Response\n- **204 No Content**: Manifest successfully deleted (or already deleted)\n- **400 Bad Request**: Invalid manifest hash format\n- **409 Conflict**: Manifest is linked to datasets and cannot be deleted\n- **500 Internal Server Error**: Store or database error\n\n## Error Codes\n- `INVALID_HASH`: Invalid hash format\n- `MANIFEST_LINKED`: Manifest is linked to datasets and cannot be deleted\n- `MANIFEST_DELETE_TRANSACTION_BEGIN_ERROR`: Failed to begin deletion transaction\n- `MANIFEST_DELETE_CHECK_LINKS_ERROR`: Failed to check if manifest is linked\n- `MANIFEST_DELETE_METADATA_DB_ERROR`: Failed to delete manifest from metadata database\n- `MANIFEST_DELETE_OBJECT_STORE_ERROR`: Failed to delete manifest from object store\n- `MANIFEST_DELETE_TRANSACTION_COMMIT_ERROR`: Failed to commit deletion transaction\n\n## Deletion Flow\nThis handler:\n1. Validates and extracts the manifest hash from the URL path\n2. Checks if the manifest is linked to any datasets\n3. If linked: Returns 409 Conflict error (deletion not allowed)\n4. If not linked:\n - Deletes manifest record from metadata database\n - Deletes manifest file from object store\n - Treats \"not found\" as success (idempotent behavior)\n5. Returns 204 No Content on success\n\n## Safety Notes\n- Only unlinked manifests can be deleted (no dataset dependencies)\n- To delete a linked manifest, first remove all dataset associations\n- Deletion is permanent and cannot be undone", + "operationId": "manifests_delete", + "parameters": [ + { + "name": "hash", + "in": "path", + "description": "Manifest content hash", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Manifest successfully deleted (or already deleted)" + }, + "400": { + "description": "Invalid hash", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Manifest linked to datasets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/manifests/{hash}/datasets": { "get": { "tags": [ "manifests" @@ -1395,7 +1705,7 @@ "providers" ], "summary": "Handler for the `POST /providers` endpoint", - "description": "Creates a new provider configuration and stores it in the dataset store.\n\n## Request Body\n- JSON object containing provider configuration with required fields:\n - `name`: The unique identifier for the provider\n - `kind`: The type of provider (e.g., \"evm-rpc\", \"firehose\")\n - `network`: The blockchain network (e.g., \"mainnet\", \"goerli\", \"polygon\")\n - Additional provider-specific configuration fields as needed\n\n## Response\n- **201 Created**: Provider created successfully\n- **400 Bad Request**: Invalid request body or provider configuration\n- **409 Conflict**: Provider with the same name already exists\n- **500 Internal Server Error**: Store error\n\n## Error Codes\n- `INVALID_REQUEST_BODY`: Malformed JSON request body\n- `DATA_CONVERSION_ERROR`: Failed to convert JSON to TOML format\n- `PROVIDER_CONFLICT`: Provider name already exists\n- `STORE_ERROR`: Failed to save provider configuration\n\nThis handler:\n- Validates and extracts the provider data from the JSON request body\n- Converts additional JSON configuration fields to TOML format\n- Registers the provider configuration in the dataset store\n- Returns HTTP 201 on successful creation", + "description": "Creates or updates a provider configuration in the dataset store.\n\n## Request Body\n- JSON object containing provider configuration with required fields:\n - `name`: The unique identifier for the provider\n - `kind`: The type of provider (e.g., \"evm-rpc\", \"firehose\")\n - Additional provider-specific configuration fields as needed (e.g., `network`, `url`)\n\n## Response\n- **201 Created**: Provider created or updated successfully\n- **400 Bad Request**: Invalid request body or provider configuration\n- **500 Internal Server Error**: Store error\n\n## Error Codes\n- `INVALID_REQUEST_BODY`: Malformed JSON request body\n- `DATA_CONVERSION_ERROR`: Failed to convert JSON to TOML format\n- `STORE_ERROR`: Failed to save provider configuration\n\nThis handler:\n- Validates and extracts the provider data from the JSON request body\n- Converts additional JSON configuration fields to TOML format\n- Registers the provider configuration in the dataset store (overwrites if exists)\n- Returns HTTP 201 on successful creation", "operationId": "providers_create", "requestBody": { "content": { @@ -1409,7 +1719,7 @@ }, "responses": { "201": { - "description": "Provider created successfully" + "description": "Provider created or updated successfully" }, "400": { "description": "Invalid request body or provider configuration", @@ -1421,16 +1731,6 @@ } } }, - "409": { - "description": "Provider with the same name already exists", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, "500": { "description": "Internal server error", "content": { @@ -1450,7 +1750,7 @@ "providers" ], "summary": "Handler for the `GET /providers/{name}` endpoint", - "description": "Retrieves and returns complete information for a specific provider configuration by its name from the dataset store.\n\n## Security Note\n\nThis endpoint returns the **complete provider configuration** including all configuration\ndetails stored in the provider files. Ensure that sensitive information such as API keys,\nconnection strings, and credentials are not stored in provider configuration files or\nare properly filtered before storage.\n\n## Path Parameters\n- `name`: The unique name/identifier of the provider to retrieve\n\n## Response\n- **200 OK**: Returns the provider metadata as JSON\n- **400 Bad Request**: Invalid provider name format\n- **404 Not Found**: Provider with the given name does not exist\n\n## Error Codes\n- `INVALID_PROVIDER_NAME`: The provided name is invalid or malformed\n- `PROVIDER_NOT_FOUND`: No provider exists with the given name\n\nThis handler:\n- Validates and extracts the provider name from the URL path\n- Accesses cached provider configurations from the dataset store\n- Returns 404 if provider not found in cache; store/parsing errors are logged during cache loading\n- Converts provider configuration to API response format including full configuration details\n\nNote: Empty provider names (e.g., `GET /providers/`) are handled by Axum's routing layer\nand return 404 before reaching this handler, ensuring no conflict with the get_all endpoint.", + "description": "Retrieves and returns complete information for a specific provider configuration by its name from the dataset store.\n\n## Security Note\n\nThis endpoint returns the **complete provider configuration** including all configuration\ndetails stored in the provider files. Ensure that sensitive information such as API keys,\nconnection strings, and credentials are not stored in provider configuration files or\nare properly filtered before storage.\n\n## Path Parameters\n- `name`: The unique name/identifier of the provider to retrieve\n\n## Response\n- **200 OK**: Returns the provider metadata as JSON\n- **400 Bad Request**: Invalid provider name format\n- **404 Not Found**: Provider with the given name does not exist\n- **500 Internal Server Error**: Failed to convert provider configuration\n\n## Error Codes\n- `INVALID_PROVIDER_NAME`: The provided name is invalid or malformed\n- `PROVIDER_NOT_FOUND`: No provider exists with the given name\n- `PROVIDER_CONVERSION_ERROR`: Failed to convert provider configuration to response format\n\nThis handler:\n- Validates and extracts the provider name from the URL path\n- Accesses cached provider configurations from the dataset store\n- Returns 404 if provider not found in cache; store/parsing errors are logged during cache loading\n- Converts provider configuration to API response format including full configuration details\n\nNote: Empty provider names (e.g., `GET /providers/`) are handled by Axum's routing layer\nand return 404 before reaching this handler, ensuring no conflict with the get_all endpoint.", "operationId": "providers_get", "parameters": [ { @@ -1479,13 +1779,649 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Provider not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "providers" + ], + "summary": "Handler for the `DELETE /providers/{name}` endpoint", + "description": "Deletes a specific provider configuration by its name from the dataset store.\n\nThis operation is idempotent - deleting a non-existent provider returns success.\n\n## Path Parameters\n- `name`: The unique name/identifier of the provider to delete\n\n## Response\n- **204 No Content**: Provider successfully deleted (or did not exist)\n- **400 Bad Request**: Invalid provider name format\n- **500 Internal Server Error**: Store error occurred during deletion\n\n## Error Codes\n- `INVALID_PROVIDER_NAME`: The provided name is invalid or malformed\n- `STORE_ERROR`: Failed to delete provider configuration from store\n\nThis handler:\n- Validates and extracts the provider name from the URL path\n- Attempts to delete the provider configuration from both store and cache\n- Returns 204 even if the provider does not exist (idempotent behavior)\n\n## Safety Notes\n- Deletion removes both the configuration file from storage and the cached entry\n- Once deleted, the provider configuration cannot be recovered\n- Any datasets using this provider may fail until a new provider is configured", + "operationId": "providers_delete", + "parameters": [ + { + "name": "name", + "in": "path", + "description": "Provider name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Provider successfully deleted (or did not exist)" + }, + "400": { + "description": "Invalid provider name", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/revisions": { + "get": { + "tags": [ + "revisions" + ], + "summary": "Handler for the `GET /revisions` endpoint", + "description": "Returns physical table revisions with cursor-based pagination and optional active\nstatus filtering.\n\n## Query Parameters\n- `active` (optional): Filter by active status (`true` or `false`)\n- `limit` (optional): Maximum number of revisions to return (default: 100)\n- `last_id` (optional): Cursor for pagination — ID of the last revision from the\n previous page. Omit for the first page.\n\n## Response\n- **200 OK**: Successfully retrieved revisions\n- **400 Bad Request**: Invalid query parameters\n- **500 Internal Server Error**: Database error during listing\n\n## Error Codes\n- `INVALID_QUERY_PARAMETERS`: Invalid query parameters\n- `LIST_ALL_TABLE_REVISIONS_ERROR`: Failed to list table revisions\n\nThis handler:\n- Validates and extracts optional `active`, `limit`, and `last_id` query parameters\n- Calls the data store to list table revisions with the given filters and cursor\n- Returns revision information as a JSON array", + "operationId": "list_revisions", + "parameters": [ + { + "name": "active", + "in": "query", + "description": "Filter by active status", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of revisions to return (default: 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "last_id", + "in": "query", + "description": "Cursor for pagination: ID of the last revision from the previous page", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved revisions", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RevisionInfo" + } + } + } + } + }, + "400": { + "description": "Invalid query parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "revisions" + ], + "summary": "Handler for the `POST /revisions` endpoint", + "description": "Creates an inactive, unlinked physical table revision record from a given path.\nThis is a low-level API that only inserts into `physical_table_revisions`.\nIt does NOT create `physical_tables` entries or activate the revision.\n\n## Request Body\n- `dataset`: Dataset reference (namespace/name or with revision)\n- `table_name`: Name of the table to create a revision for\n- `path`: Physical table revision path in object storage\n\n## Response\n- **200 OK**: Successfully created the table revision\n- **404 Not Found**: Dataset or revision not found\n- **500 Internal Server Error**: Database error during creation\n\n## Error Codes\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `REGISTER_TABLE_REVISION_ERROR`: Failed to register the table revision\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n\nThis handler:\n1. Resolves the dataset reference to a manifest hash\n2. Idempotently creates a revision record in the metadata database\n3. Returns the assigned location ID", + "operationId": "create_table_revision", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePayload" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully created the table revision", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRevisionResponse" + } + } + } + }, + "404": { + "description": "Dataset, revision, or table not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/revisions/deactivate": { + "post": { + "tags": [ + "revisions" + ], + "summary": "Handler for the `POST /revisions/deactivate` endpoint", + "description": "Deactivates all revisions for a specific table.\n\n## Request Body\n- `dataset`: Dataset reference (namespace/name or with revision)\n- `table_name`: Name of the table whose revisions to deactivate\n\n## Response\n- **200 OK**: Successfully deactivated all table revisions\n- **404 Not Found**: Dataset or revision not found\n- **500 Internal Server Error**: Database error during deactivation\n\n## Error Codes\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `TABLE_NOT_FOUND`: No physical table exists for the dataset and table name\n- `DEACTIVATE_TABLE_REVISION_ERROR`: Failed to deactivate the table revisions\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n\n## Behavior\nThis endpoint resolves the dataset reference to a manifest hash, then marks all\nrevisions for the specified table as inactive.", + "operationId": "deactivate_table_revision", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeactivationPayload" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully deactivated the table revisions" + }, + "404": { + "description": "Dataset or revision not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/revisions/{id}": { + "get": { + "tags": [ + "revisions" + ], + "summary": "Handler for the `GET /revisions/{id}` endpoint", + "description": "Returns a specific revision by location ID.\n\n## Path Parameters\n- `id`: The unique identifier of the revision (must be a valid LocationId)\n\n## Response\n- **200 OK**: Successfully retrieved revision\n- **400 Bad Request**: Invalid path parameters\n- **404 Not Found**: Revision not found\n- **500 Internal Server Error**: Database error during retrieval\n\n## Error Codes\n- `INVALID_PATH_PARAMETERS`: Invalid path parameters\n- `REVISION_NOT_FOUND`: No revision exists with the specified location ID\n- `GET_REVISION_BY_LOCATION_ID_ERROR`: Failed to retrieve revision from database\n\n## Behavior\nThis endpoint looks up a single physical table revision by its location ID\nand returns its details including path, active status, writer, and metadata.", + "operationId": "get_revision_by_location_id", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Revision ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved revision", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevisionInfo" + } + } + } + }, + "400": { + "description": "Invalid path parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Revision not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "revisions" + ], + "summary": "Handler for the `DELETE /revisions/{id}` endpoint", + "description": "Deletes a physical table revision by its location ID.\n\n## Path Parameters\n- `id`: The unique identifier of the revision (must be a valid LocationId)\n\n## Response\n- **204 No Content**: Revision deleted successfully\n- **400 Bad Request**: Invalid path parameters\n- **404 Not Found**: Revision not found\n- **409 Conflict**: Revision is currently active or writer job is not in a terminal state\n- **500 Internal Server Error**: Database error\n\n## Error Codes\n- `INVALID_PATH_PARAMETERS`: Invalid path parameters\n- `REVISION_NOT_FOUND`: No revision exists with the specified location ID\n- `REVISION_IS_ACTIVE`: The revision is currently active and must be deactivated before deletion\n- `WRITER_JOB_NOT_TERMINAL`: The revision's writer job is still running and must reach a terminal state before deletion\n- `GET_REVISION_BY_LOCATION_ID_ERROR`: Failed to retrieve revision from database\n- `GET_WRITER_JOB_ERROR`: Failed to retrieve writer job from database\n- `DELETE_TABLE_REVISION_ERROR`: Failed to delete revision from database\n\n## Behavior\nThis handler:\n- Validates and extracts the location ID from the URL path\n- Retrieves the revision to verify it exists\n- Checks that the revision is inactive (active revisions cannot be deleted)\n- Checks that any writer job is in a terminal state (completed, stopped, or failed)\n- Deletes the revision and all associated file metadata (via CASCADE)", + "operationId": "delete_table_revision", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Revision ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "Revision deleted successfully" + }, + "400": { + "description": "Invalid path parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Revision not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Revision is active or writer job is not terminal", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/revisions/{id}/activate": { + "post": { + "tags": [ + "revisions" + ], + "summary": "Handler for the `POST /revisions/{id}/activate` endpoint", + "description": "Activates a specific table revision by location ID.\n\n## Path Parameters\n- `id`: Location ID of the revision to activate\n\n## Request Body\n- `dataset`: Dataset reference (namespace/name or with revision)\n- `table_name`: Name of the table whose revision to activate\n\n## Response\n- **200 OK**: Successfully activated the table revision\n- **400 Bad Request**: Invalid path parameters\n- **404 Not Found**: Dataset or revision not found\n- **500 Internal Server Error**: Database error during activation\n\n## Error Codes\n- `INVALID_PATH_PARAMETERS`: Invalid location ID in URL path\n- `DATASET_NOT_FOUND`: The specified dataset or revision does not exist\n- `TABLE_NOT_IN_MANIFEST`: The table name does not exist in the dataset manifest\n- `TABLE_NOT_REGISTERED`: The table is not registered in the data store\n- `GET_DATASET_ERROR`: Failed to load the dataset from its manifest\n- `ACTIVATE_TABLE_REVISION_ERROR`: Failed to activate the table revision\n- `RESOLVE_REVISION_ERROR`: Failed to resolve revision to manifest hash\n\n## Behavior\nThis endpoint resolves the dataset reference to a manifest hash, validates that\nthe table name exists in the dataset manifest, then atomically deactivates all\nexisting revisions for the table and marks the specified revision as active.", + "operationId": "activate_table_revision", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Location ID of the revision to activate", + "required": true, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivationPayload" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully activated the table revision" + }, + "400": { + "description": "Invalid path parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Dataset or revision not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/revisions/{id}/prune": { + "delete": { + "tags": [ + "revisions" + ], + "summary": "Handler for the `DELETE /revisions/{id}/prune` endpoint", + "description": "Prunes non-canonical segments from a physical table revision by scheduling\nthem for garbage collection via the GC manifest.\n\n## Path Parameters\n- `id`: The unique identifier of the revision (must be a valid LocationId)\n\n## Query Parameters\n- `before_block` (optional): Only prune segments ending before this block number\n- `gc_delay_secs` (optional): Seconds before files become eligible for GC deletion (default: 3600)\n\n## Response\n- **200 OK**: Non-canonical segments scheduled for GC successfully\n- **400 Bad Request**: Invalid path or query parameters\n- **404 Not Found**: Revision not found\n- **409 Conflict**: Writer job is not terminal\n- **500 Internal Server Error**: Database or object store error\n\n## Error Codes\n- `INVALID_PATH_PARAMETERS`: Invalid path parameters\n- `INVALID_QUERY_PARAMETERS`: Invalid query parameters\n- `REVISION_NOT_FOUND`: No revision exists with the specified location ID\n- `WRITER_JOB_NOT_TERMINAL`: The revision's writer job is still running and must reach a terminal state before pruning\n- `GET_REVISION_BY_LOCATION_ID_ERROR`: Failed to retrieve revision from database\n- `GET_WRITER_JOB_ERROR`: Failed to retrieve writer job from database\n- `GET_FILES_ERROR`: Failed to retrieve file metadata\n- `PARSE_METADATA_ERROR`: Failed to parse parquet metadata\n- `CANONICAL_CHAIN_PANICKED`: Canonical chain computation task panicked or was aborted\n- `PRUNE_ERROR`: Failed to prune non-canonical segments\n\n## Behavior\nThis handler:\n- Validates and extracts the location ID from the URL path\n- Retrieves the revision to verify it exists\n- Checks that any writer job is in a terminal state (completed, stopped, or failed)\n- Retrieves all file metadata for the revision\n- Computes the canonical chain of segments\n- Identifies non-canonical segments (segments not in the canonical chain)\n- Optionally filters by block number (only segments ending before the specified block)\n- Schedules non-canonical files for garbage collection via the GC manifest\n- Preserves the revision record and all canonical segments", + "operationId": "prune_table_revision", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Revision ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "before_block", + "in": "query", + "description": "Only prune segments ending before this block number", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "gc_delay_secs", + "in": "query", + "description": "Seconds before files become eligible for GC deletion (default: 3600)", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Non-canonical segments scheduled for GC successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PruneResponse" + } + } + } + }, + "400": { + "description": "Invalid path or query parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Revision not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Writer job is not terminal", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/revisions/{id}/restore": { + "post": { + "tags": [ + "revisions" + ], + "summary": "Handler for the `POST /revisions/{id}/restore` endpoint", + "description": "Restores a revision by re-registering its files from object storage.\n\n## Path Parameters\n- `id`: The unique identifier of the revision (must be a valid LocationId)\n\n## Response\n- **200 OK**: Revision restored successfully\n- **400 Bad Request**: Invalid path parameters\n- **404 Not Found**: Revision not found\n- **500 Internal Server Error**: Database or file registration error\n\n## Error Codes\n- `INVALID_PATH_PARAMETERS`: Invalid path parameters\n- `REVISION_NOT_FOUND`: No revision exists with the specified location ID\n- `GET_REVISION_BY_LOCATION_ID_ERROR`: Failed to retrieve revision from database\n- `REGISTER_FILES_ERROR`: Failed to register revision files from object storage\n\n## Behavior\nThis endpoint looks up the physical table revision by its location ID, then\nlists all files in the revision's object storage directory. For each file,\nit reads Amp-specific Parquet metadata and registers it in the metadata database.", + "operationId": "restore_revision", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Revision ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Revision restored successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestoreResponse" + } + } + } + }, + "400": { + "description": "Invalid path parameters", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Revision not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/revisions/{id}/truncate": { + "delete": { + "tags": [ + "revisions" + ], + "summary": "Handler for the `DELETE /revisions/{id}/truncate` endpoint", + "description": "Truncates a physical table revision by deleting all associated files from\nobject storage and their corresponding metadata, then deletes the revision.\n\n## Path Parameters\n- `id`: The unique identifier of the revision (must be a valid LocationId)\n\n## Response\n- **200 OK**: Revision truncated and deleted successfully\n- **400 Bad Request**: Invalid path parameters\n- **404 Not Found**: Revision not found\n- **409 Conflict**: Revision is currently active, writer job is not terminal,\n or file metadata rows remain after truncation\n- **500 Internal Server Error**: Database or object store error\n\n## Error Codes\n- `INVALID_PATH_PARAMETERS`: Invalid path parameters\n- `INVALID_QUERY_PARAMETERS`: Invalid query parameters\n- `REVISION_NOT_FOUND`: No revision exists with the specified location ID\n- `REVISION_IS_ACTIVE`: The revision is currently active and must be deactivated before truncation\n- `WRITER_JOB_NOT_TERMINAL`: The revision's writer job is still running and must reach a terminal state before truncation\n- `GET_REVISION_BY_LOCATION_ID_ERROR`: Failed to retrieve revision from database\n- `GET_WRITER_JOB_ERROR`: Failed to retrieve writer job from database\n- `TRUNCATE_ERROR`: Failed to truncate revision files\n- `VERIFY_FILE_METADATA_ERROR`: Failed to verify file metadata cleanup\n- `FILE_METADATA_REMAINING`: File metadata rows remain after truncation\n- `DELETE_REVISION_ERROR`: Failed to delete revision row\n\n## Behavior\nThis handler:\n- Validates and extracts the location ID from the URL path\n- Retrieves the revision to verify it exists\n- Checks that the revision is inactive (active revisions cannot be truncated)\n- Checks that any writer job is in a terminal state (completed, stopped, or failed)\n- Deletes all files from object storage and their metadata rows with bounded concurrency\n- Verifies no file metadata rows remain for the revision\n- Deletes the revision record from the metadata database", + "operationId": "truncate_table_revision", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Revision ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "concurrency", + "in": "query", + "description": "Max concurrent file deletions (default: 10)", + "required": false, + "schema": { + "type": "integer", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "Revision truncated and deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TruncateResponse" } } } }, - "404": { - "description": "Provider not found", + "400": { + "description": "Invalid path parameters", "content": { "application/json": { "schema": { @@ -1494,8 +2430,8 @@ } } }, - "500": { - "description": "Internal server error", + "404": { + "description": "Revision not found", "content": { "application/json": { "schema": { @@ -1503,33 +2439,9 @@ } } } - } - } - }, - "delete": { - "tags": [ - "providers" - ], - "summary": "Handler for the `DELETE /providers/{name}` endpoint", - "description": "Deletes a specific provider configuration by its name from the dataset store.\n\nThis operation is idempotent - deleting a non-existent provider returns success.\n\n## Path Parameters\n- `name`: The unique name/identifier of the provider to delete\n\n## Response\n- **204 No Content**: Provider successfully deleted (or did not exist)\n- **400 Bad Request**: Invalid provider name format\n- **500 Internal Server Error**: Store error occurred during deletion\n\n## Error Codes\n- `INVALID_PROVIDER_NAME`: The provided name is invalid or malformed\n- `STORE_ERROR`: Failed to delete provider configuration from store\n\nThis handler:\n- Validates and extracts the provider name from the URL path\n- Attempts to delete the provider configuration from both store and cache\n- Returns 204 even if the provider does not exist (idempotent behavior)\n\n## Safety Notes\n- Deletion removes both the configuration file from storage and the cached entry\n- Once deleted, the provider configuration cannot be recovered\n- Any datasets using this provider may fail until a new provider is configured", - "operationId": "providers_delete", - "parameters": [ - { - "name": "name", - "in": "path", - "description": "Provider name", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Provider successfully deleted (or did not exist)" }, - "400": { - "description": "Invalid provider name", + "409": { + "description": "Revision is active, writer job is not terminal, or file metadata remaining", "content": { "application/json": { "schema": { @@ -1556,14 +2468,14 @@ "tags": [ "schema" ], - "summary": "Handler for the `/schema` endpoint that provides SQL schema analysis.", - "description": "This endpoint performs comprehensive SQL validation and schema inference by:\n1. **Parsing SQL**: Validates syntax using DataFusion's SQL parser\n2. **Loading Datasets**: Retrieves actual dataset definitions from the registry\n3. **Schema Resolution**: Creates planning context with real table schemas from stored datasets\n4. **Schema Inference**: Uses DataFusion's query planner to determine output schema without execution\n5. **Special Fields**: Optionally prepends `SPECIAL_BLOCK_NUM` field for SQL datasets\n6. **Network Extraction**: Identifies which blockchain networks the query references\n\nThe validation works with real registered datasets and their actual schemas,\nensuring datasets exist, tables are valid, and column references are correct.\nThis enables accurate schema introspection for query builders and dataset development tools.\n\n## Request Body\n- `sql_query`: The SQL query to analyze\n- `is_sql_dataset`: (optional) Whether this is a SQL dataset (affects block number field inclusion)\n\n## Response\n- **200 OK**: Returns the schema and networks used by the query\n- **400 Bad Request**: SQL parse error\n- **500 Internal Server Error**: Dataset store or planning error\n\n## Error Codes\n- `SQL_PARSE_ERROR`: Failed to parse the SQL query\n- `DATASET_STORE_ERROR`: Failed to load datasets from store\n- `PLANNING_ERROR`: Failed to determine output schema", + "summary": "Handler for the `POST /schema` endpoint", + "description": "Analyzes SQL queries and returns the output schema without executing the query.\nPerforms comprehensive validation and schema inference using real registered datasets\nand their actual schemas.\n\n## Request Body\n- `dependencies`: External dataset dependencies mapped by alias\n- `tables`: Table definitions mapped by table name (optional if functions provided)\n- `functions`: Function names defined in dataset config (optional if tables provided)\n\n## Response\n- **200 OK**: Returns the inferred schema and networks referenced by the query\n- **400 Bad Request**: Invalid SQL syntax, table references, or function format\n- **404 Not Found**: Referenced dataset does not exist\n- **500 Internal Server Error**: Dataset store, planning, or internal errors\n\n## Error Codes\n- `INVALID_PAYLOAD_FORMAT`: Request JSON is malformed or missing required fields\n- `EMPTY_TABLES_AND_FUNCTIONS`: No tables or functions provided (at least one is required)\n- `INVALID_TABLE_SQL`: SQL syntax error in table definition\n- `NON_INCREMENTAL_QUERY`: SQL query is non-incremental\n- `SELF_REFERENCING_TABLE`: A table references itself via `self.`\n- `CYCLIC_DEPENDENCY`: Inter-table dependencies form a cycle\n- `TABLE_REFERENCE_RESOLUTION`: Failed to extract table references from SQL\n- `NO_TABLE_REFERENCES`: Table SQL does not reference any source tables\n- `FUNCTION_REFERENCE_RESOLUTION`: Failed to extract function references from SQL\n- `DEPENDENCY_NOT_FOUND`: Referenced dependency does not exist\n- `DEPENDENCY_MANIFEST_LINK_CHECK`: Failed to verify manifest link for dependency\n- `DEPENDENCY_VERSION_RESOLUTION`: Failed to resolve version for dependency\n- `CATALOG_QUALIFIED_TABLE`: Table uses unsupported catalog qualification\n- `UNQUALIFIED_TABLE`: Table missing required dataset qualification\n- `INVALID_TABLE_NAME`: Table name violates SQL identifier rules\n- `INVALID_DEPENDENCY_ALIAS_FOR_TABLE_REF`: Dependency alias in table reference is invalid\n- `INVALID_DEPENDENCY_ALIAS_FOR_FUNCTION_REF`: Dependency alias in function reference is invalid\n- `CATALOG_QUALIFIED_FUNCTION`: Function uses unsupported catalog qualification\n- `DEPENDENCY_ALIAS_NOT_FOUND`: Referenced alias not in dependencies\n- `DATASET_NOT_FOUND`: Referenced dataset does not exist\n- `GET_DATASET_ERROR`: Failed to retrieve dataset from store\n- `ETH_CALL_UDF_CREATION_ERROR`: Failed to create eth_call UDF\n- `TABLE_NOT_FOUND_IN_DATASET`: Table not found in referenced dataset\n- `FUNCTION_NOT_FOUND_IN_DATASET`: Function not found in referenced dataset\n- `ETH_CALL_NOT_AVAILABLE`: eth_call function not available for dataset\n- `SESSION_CONFIG_ERROR`: Failed to create DataFusion session configuration\n- `SCHEMA_INFERENCE`: Failed to infer output schema from query\n\n## Schema Analysis Process\n1. **Parse SQL**: Validates syntax using DataFusion's SQL parser\n2. **Load Datasets**: Retrieves dataset definitions from the registry for all referenced datasets\n3. **Create Planning Context**: Builds planning context with real table schemas from stored datasets\n4. **Infer Schema**: Uses DataFusion's query planner to determine output schema without executing the query\n5. **Prepend Special Fields**: Adds `RESERVED_BLOCK_NUM_COLUMN_NAME` field to the output schema\n6. **Extract Networks**: Identifies which blockchain networks are referenced by the query\n\n# Panics\n\nPanics if `resolve_inter_table_order` returns a table name that was not in the\noriginal statements map. This is structurally impossible because the sort only\nreturns keys from its input.", "operationId": "schema_analyze", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/OutputSchemaRequest" + "$ref": "#/components/schemas/SchemaRequest" } } }, @@ -1575,13 +2487,23 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/OutputSchemaResponse" + "$ref": "#/components/schemas/SchemaResponse" } } } }, "400": { - "description": "SQL parse error", + "description": "Client error: Invalid SQL, table references, or function syntax", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Dataset not found", "content": { "application/json": { "schema": { @@ -1591,7 +2513,7 @@ } }, "500": { - "description": "Dataset store or planning error", + "description": "Server error: Dataset store, planning, or internal failures", "content": { "application/json": { "schema": { @@ -1609,7 +2531,7 @@ "workers" ], "summary": "Handler for the `GET /workers` endpoint", - "description": "Retrieves and returns a list of all workers from the metadata database.\n\n## Response\n- **200 OK**: Returns all workers with their information\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `METADATA_DB_LIST_ERROR`: Failed to retrieve workers list from database\n\nThis handler:\n- Fetches all workers from the metadata database\n- Converts worker records to API response format with ISO 8601 RFC3339 timestamps\n- Returns a structured response with worker information including node IDs and last heartbeat times", + "description": "Retrieves and returns a list of all workers from the scheduler.\n\n## Response\n- **200 OK**: Returns all workers with their information\n- **500 Internal Server Error**: Scheduler query error\n\n## Error Codes\n- `SCHEDULER_LIST_WORKERS_ERROR`: Failed to retrieve workers list from scheduler\n\nThis handler:\n- Fetches all workers from the scheduler\n- Converts worker records to API response format with ISO 8601 RFC3339 timestamps\n- Returns a structured response with worker information including node IDs and last heartbeat times", "operationId": "workers_list", "responses": { "200": { @@ -1641,7 +2563,7 @@ "workers" ], "summary": "Handler for the `GET /workers/{id}` endpoint", - "description": "Retrieves and returns a specific worker by its node ID from the metadata database.\n\n## Path Parameters\n- `id`: The unique node identifier of the worker to retrieve\n\n## Response\n- **200 OK**: Returns the worker information as JSON with detailed metadata\n- **400 Bad Request**: Invalid node ID format (not parseable as NodeId)\n- **404 Not Found**: Worker with the given node ID does not exist\n- **500 Internal Server Error**: Database connection or query error\n\n## Error Codes\n- `INVALID_WORKER_ID`: The provided ID is not a valid worker node identifier\n- `WORKER_NOT_FOUND`: No worker exists with the given node ID\n- `METADATA_DB_GET_BY_ID_ERROR`: Failed to retrieve worker from database", + "description": "Retrieves and returns a specific worker by its node ID from the scheduler.\n\n## Path Parameters\n- `id`: The unique node identifier of the worker to retrieve\n\n## Response\n- **200 OK**: Returns the worker information as JSON with detailed metadata\n- **400 Bad Request**: Invalid node ID format (not parseable as NodeId)\n- **404 Not Found**: Worker with the given node ID does not exist\n- **500 Internal Server Error**: Scheduler query error\n\n## Error Codes\n- `INVALID_WORKER_ID`: The provided ID is not a valid worker node identifier\n- `WORKER_NOT_FOUND`: No worker exists with the given node ID\n- `SCHEDULER_GET_WORKER_ERROR`: Failed to retrieve worker from scheduler", "operationId": "workers_get", "parameters": [ { @@ -1701,6 +2623,209 @@ }, "components": { "schemas": { + "ActivationPayload": { + "type": "object", + "description": "Payload for activating a table revision", + "required": [ + "table_name", + "dataset" + ], + "properties": { + "dataset": { + "type": "string", + "description": "Dataset reference" + }, + "table_name": { + "type": "string", + "description": "Table name" + } + } + }, + "CreateJobRequest": { + "oneOf": [ + { + "allOf": [ + { + "type": "object", + "description": "The job descriptor fields (flattened from the GC job descriptor)." + }, + { + "type": "object", + "properties": { + "retry_strategy": { + "type": [ + "object", + "null" + ], + "description": "Optional retry strategy controlling how failed jobs are retried." + }, + "worker_id": { + "type": [ + "string", + "null" + ], + "description": "Optional worker selector (exact ID or glob pattern)." + } + } + }, + { + "type": "object", + "description": "Schedule a garbage collection job for a physical table revision.", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "gc" + ] + } + } + } + ], + "description": "Schedule a garbage collection job for a physical table revision." + }, + { + "allOf": [ + { + "type": "object", + "description": "The job descriptor fields (flattened from the raw materialization descriptor)." + }, + { + "type": "object", + "properties": { + "retry_strategy": { + "type": [ + "object", + "null" + ], + "description": "Optional retry strategy controlling how failed jobs are retried." + }, + "worker_id": { + "type": [ + "string", + "null" + ], + "description": "Optional worker selector (exact ID or glob pattern)." + } + } + }, + { + "type": "object", + "description": "Schedule a raw dataset materialization job.", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "materialize-raw" + ] + } + } + } + ], + "description": "Schedule a raw dataset materialization job." + }, + { + "allOf": [ + { + "type": "object", + "description": "The job descriptor fields (flattened from the derived materialization descriptor)." + }, + { + "type": "object", + "properties": { + "retry_strategy": { + "type": [ + "object", + "null" + ], + "description": "Optional retry strategy controlling how failed jobs are retried." + }, + "worker_id": { + "type": [ + "string", + "null" + ], + "description": "Optional worker selector (exact ID or glob pattern)." + } + } + }, + { + "type": "object", + "description": "Schedule a derived dataset materialization job.", + "required": [ + "kind" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "materialize-derived" + ] + } + } + } + ], + "description": "Schedule a derived dataset materialization job." + } + ], + "description": "Request body for creating a job.\n\nDispatches on the `kind` field to determine the job type.\nFields for each variant are defined by the corresponding job descriptor type." + }, + "CreateJobResponse": { + "type": "object", + "description": "Response body for a created job.", + "required": [ + "job_id" + ], + "properties": { + "job_id": { + "type": "integer", + "format": "int64", + "description": "The ID of the scheduled job." + } + } + }, + "CreatePayload": { + "type": "object", + "description": "Payload for creating a table revision", + "required": [ + "table_name", + "dataset", + "path" + ], + "properties": { + "dataset": { + "type": "string", + "description": "Dataset reference" + }, + "path": { + "type": "string", + "description": "Revision path in object storage" + }, + "table_name": { + "type": "string", + "description": "Table name" + } + } + }, + "CreateRevisionResponse": { + "type": "object", + "description": "Response for creating a table revision", + "required": [ + "location_id" + ], + "properties": { + "location_id": { + "type": "integer", + "format": "int64", + "description": "Location ID assigned to the new revision" + } + } + }, "Dataset": { "type": "object", "description": "Dataset information\n\nRepresents a dataset tag with its namespace, name, and version.", @@ -1732,9 +2857,16 @@ "name", "revision", "manifest_hash", - "kind" + "kind", + "start_block", + "finalized_blocks_only", + "tables" ], "properties": { + "finalized_blocks_only": { + "type": "boolean", + "description": "Finalized blocks only" + }, "kind": { "type": "string", "description": "Dataset kind" @@ -1754,6 +2886,19 @@ "revision": { "type": "string", "description": "Revision requested" + }, + "start_block": { + "type": "integer", + "format": "int64", + "description": "Starting block", + "minimum": 0 + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tables" } } }, @@ -1806,6 +2951,24 @@ } } }, + "DeactivationPayload": { + "type": "object", + "description": "Payload for deactivating a table revision", + "required": [ + "table_name", + "dataset" + ], + "properties": { + "dataset": { + "type": "string", + "description": "Dataset reference" + }, + "table_name": { + "type": "string", + "description": "Table name" + } + } + }, "DeployRequest": { "type": "object", "description": "Request for deploying a dataset", @@ -1819,6 +2982,24 @@ "format": "int32", "description": "Number of parallel workers to run\n\nEach worker will be responsible for an equal number of blocks.\nFor example, if extracting blocks 0-10,000,000 with parallelism=10,\neach worker will handle a contiguous section of 1 million blocks.\n\nOnly applicable to raw datasets (EVM RPC, Firehose, etc.).\nDerived datasets ignore this parameter.\n\nDefaults to 1 if not specified.", "minimum": 0 + }, + "retry_strategy": { + "type": [ + "object", + "null" + ], + "description": "Optional retry strategy controlling how failed jobs are retried.\n\nSupports three strategies:\n- `none`: Never retry — fail immediately on first error.\n- `bounded`: Retry up to `max_attempts` times with configurable backoff.\n- `unless_stopped`: Retry indefinitely until the job is explicitly stopped.\n\nIf not specified, the scheduler applies its default strategy." + }, + "verify": { + "type": "boolean", + "description": "Enable cryptographic verification of EVM block data during extraction.\n\nWhen enabled, verifies block hashes, transaction roots, and receipt roots\nbefore writing data to storage. Only applicable to EVM raw datasets.\nVerification failures are retryable errors.\n\nDefaults to false if not specified." + }, + "worker_id": { + "type": [ + "string", + "null" + ], + "description": "Optional worker selector - either an exact worker ID or a glob pattern.\n\nExamples:\n- `\"worker-node-0\"` - assigns to the specific worker with ID \"worker-node-0\"\n- `\"worker-eth-*\"` - randomly selects from workers matching the pattern\n\nIf not specified, a worker will be selected randomly from all available workers.\nIf a glob pattern is provided, one matching worker will be randomly selected\nThe worker must be active (has sent heartbeats recently) for the deployment to succeed." } } }, @@ -1917,219 +3098,179 @@ } } }, - "FileListInfo": { + "JobEventDetailResponse": { "type": "object", - "description": "Minimal file information for location file listings\n\nThis struct represents essential file metadata for list endpoints,\ncontaining only the most relevant information needed for file browsing\nwithin a location context.", + "description": "Response body for GET /jobs/{id}/events/{event_id} endpoint.", "required": [ "id", - "file_name" + "job_id", + "created_at", + "node_id", + "event_type" ], "properties": { - "file_name": { + "created_at": { "type": "string", - "description": "Name of the file (e.g., \"blocks_0000000000_0000099999.parquet\")" + "description": "Event timestamp in ISO 8601 / RFC 3339 format" + }, + "detail": { + "description": "Optional structured detail payload" + }, + "event_type": { + "type": "string", + "description": "Event type (e.g., SCHEDULED, RUNNING, COMPLETED, ERROR, FATAL, STOPPED)" }, "id": { "type": "integer", "format": "int64", - "description": "Unique identifier for this file (64-bit integer)" + "description": "Event ID" }, - "object_size": { - "type": [ - "integer", - "null" - ], + "job_id": { + "type": "integer", "format": "int64", - "description": "Size of the file object in bytes" + "description": "Job ID" + }, + "node_id": { + "type": "string", + "description": "ID of the worker node that recorded this event" } } }, - "JobInfo": { + "JobEventInfo": { "type": "object", - "description": "Job information returned by the API\n\nThis struct represents job metadata in a format suitable for API responses.\nIt contains essential information about a job without exposing internal\ndatabase implementation details.", + "description": "A single job lifecycle event.", "required": [ "id", + "created_at", "node_id", - "status", - "descriptor" + "event_type" ], "properties": { - "descriptor": { - "description": "Job descriptor containing job-specific parameters as JSON" + "created_at": { + "type": "string", + "description": "Event timestamp in ISO 8601 / RFC 3339 format" + }, + "event_type": { + "type": "string", + "description": "Event type (e.g., SCHEDULED, RUNNING, COMPLETED, ERROR, FATAL, STOPPED)" }, "id": { "type": "integer", "format": "int64", - "description": "Unique identifier for this job (64-bit integer)" + "description": "Event ID" }, "node_id": { "type": "string", - "description": "ID of the worker node this job is scheduled for" - }, - "status": { - "type": "string", - "description": "Current status of the job (Scheduled, Running, Completed, Stopped, Failed, etc.)" - } - } - }, - "JobsResponse": { - "type": "object", - "description": "API response containing job information", - "required": [ - "jobs" - ], - "properties": { - "jobs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/JobInfo" - }, - "description": "List of jobs" - }, - "next_cursor": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Cursor for the next page of results (None if no more results)" + "description": "ID of the worker node that recorded this event" } } }, - "LocationFilesResponse": { + "JobEventsResponse": { "type": "object", - "description": "Collection response for location file listings\n\nThis response structure provides paginated file data with\ncursor-based pagination support for efficient traversal.", + "description": "Response body for GET /jobs/{id}/events endpoint.", "required": [ - "files" + "job_id", + "events" ], "properties": { - "files": { + "events": { "type": "array", "items": { - "$ref": "#/components/schemas/FileListInfo" + "$ref": "#/components/schemas/JobEventInfo" }, - "description": "List of files in this page with minimal information" + "description": "List of lifecycle events" }, - "next_cursor": { - "type": [ - "integer", - "null" - ], + "job_id": { + "type": "integer", "format": "int64", - "description": "Cursor for the next page of results - use as last_file_id in next request (None if no more results)" + "description": "Job ID" } } }, - "LocationInfo": { + "JobInfo": { "type": "object", - "description": "Location information returned by the API\n\nThis struct represents location metadata from the database in a format\nsuitable for API responses. It contains all the essential information\nabout where dataset table data is stored.", + "description": "Represents job information for the API response", "required": [ "id", - "dataset", - "dataset_version", - "table", - "url", - "active" + "created_at", + "updated_at", + "node_id", + "status", + "descriptor" ], "properties": { - "active": { - "type": "boolean", - "description": "Whether this location is currently active for queries" - }, - "dataset": { + "created_at": { "type": "string", - "description": "Name of the dataset this location belongs to" + "description": "Job creation timestamp in ISO 8601 / RFC 3339 format" }, - "dataset_version": { - "type": "string", - "description": "Version of the dataset using semantic versioning (e.g., \"1.0.0\", or empty string for unversioned)" + "descriptor": { + "description": "Job descriptor containing job-specific parameters as JSON" }, "id": { "type": "integer", "format": "int64", - "description": "Unique identifier for this location (64-bit integer)" + "description": "Unique identifier for the job (64-bit integer)" + }, + "node_id": { + "type": "string", + "description": "ID of the worker node this job is scheduled for" }, - "table": { + "status": { "type": "string", - "description": "Name of the table within the dataset (e.g., \"blocks\", \"transactions\")" + "description": "Current status of the job (Scheduled, Running, Completed, Stopped, Failed, etc.)" }, - "url": { + "updated_at": { "type": "string", - "description": "Full URL to the storage location (e.g., \"s3://bucket/path/table.parquet\", \"file:///local/path/table.parquet\")" - }, - "writer": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Writer job ID (64-bit integer, if one exists)" + "description": "Job last update timestamp in ISO 8601 / RFC 3339 format" } } }, - "LocationInfoWithDetails": { + "JobProgressResponse": { "type": "object", - "description": "Location information with writer job details", + "description": "API response containing progress information for a job", "required": [ - "id", - "dataset", - "dataset_version", - "table", - "url", - "active" + "job_id", + "job_status", + "tables" ], "properties": { - "active": { - "type": "boolean", - "description": "Whether this location is currently active for queries" + "detail": { + "description": "Structured error detail (present when job is in error/fatal state)" }, - "dataset": { - "type": "string", - "description": "Name of the dataset this location belongs to" - }, - "dataset_version": { - "type": "string", - "description": "Version of the dataset using semantic versioning (e.g., \"1.0.0\", or empty string for unversioned)" - }, - "id": { + "job_id": { "type": "integer", "format": "int64", - "description": "Unique identifier for this location (64-bit integer)" - }, - "table": { - "type": "string", - "description": "Name of the table within the dataset (e.g., \"blocks\", \"transactions\")" + "description": "Job ID" }, - "url": { + "job_status": { "type": "string", - "description": "Full URL to the storage location (e.g., \"s3://bucket/path/table.parquet\", \"file:///local/path/table.parquet\")" + "description": "Current job status" }, - "writer": { - "oneOf": [ - { - "type": "null" - }, - { - "$ref": "#/components/schemas/JobInfo", - "description": "Writer job information with full details (if one exists)" - } - ] + "tables": { + "type": "object", + "description": "Progress for each table written by this job, keyed by table name", + "additionalProperties": { + "$ref": "#/components/schemas/TableProgress" + }, + "propertyNames": { + "type": "string" + } } } }, - "LocationsResponse": { + "JobsResponse": { "type": "object", - "description": "API response containing location information\n\nThis response structure provides paginated location data with\ncursor-based pagination support for efficient traversal.", + "description": "API response containing job information", "required": [ - "locations" + "jobs" ], "properties": { - "locations": { + "jobs": { "type": "array", "items": { - "$ref": "#/components/schemas/LocationInfo" + "$ref": "#/components/schemas/JobInfo" }, - "description": "List of locations in this page" + "description": "List of jobs" }, "next_cursor": { "type": [ @@ -2162,44 +3303,48 @@ } } }, - "ManifestResponse": { - "type": "object", - "description": "Response wrapper for manifest content" - }, - "OutputSchemaRequest": { + "ManifestInfo": { "type": "object", - "description": "Request payload for output schema analysis\n\nContains the SQL query to analyze and optional configuration flags.", + "description": "Summary information for a single manifest", "required": [ - "sql_query" + "hash", + "kind", + "dataset_count" ], "properties": { - "is_sql_dataset": { - "type": "boolean", - "description": "Whether this is a SQL dataset (affects block number field inclusion)\n\nWhen true, a special block number field is prepended to the schema.\nThis field tracks the block number for each row in SQL datasets." + "dataset_count": { + "type": "integer", + "format": "int64", + "description": "Number of datasets using this manifest", + "minimum": 0 }, - "sql_query": { + "hash": { + "type": "string", + "description": "Content-addressable hash (SHA-256)" + }, + "kind": { "type": "string", - "description": "The SQL query to analyze for output schema determination" + "description": "Dataset kind (e.g. \"evm-rpc\", \"solana\", \"firehose\", \"manifest\")" } } }, - "OutputSchemaResponse": { + "ManifestResponse": { + "type": "object", + "description": "Response wrapper for manifest content" + }, + "ManifestsResponse": { "type": "object", - "description": "Response returned by the output schema endpoint\n\nContains the determined schema and list of networks referenced by the query.", + "description": "Response for listing all manifests", "required": [ - "schema", - "networks" + "manifests" ], "properties": { - "networks": { + "manifests": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/ManifestInfo" }, - "description": "List of networks referenced by the query\n\nContains the network names of all datasets/tables referenced\nin the SQL query (e.g., \"mainnet\", \"polygon\", etc.)." - }, - "schema": { - "description": "The output schema for the SQL query\n\nDescribes the structure and types of columns that will be returned\nwhen executing the provided SQL query against the dataset." + "description": "List of all manifests in the system" } } }, @@ -2208,8 +3353,7 @@ "description": "Provider information used for both API requests and responses\n\nThis struct represents provider metadata and configuration in a format\nsuitable for both creating providers (POST requests) and retrieving them\n(GET responses). It includes the complete provider configuration.\n\n## Security Note\n\nThe `rest` field contains the full provider configuration. Ensure that\nsensitive information like API keys and tokens are not stored in the\nprovider configuration if this data will be exposed through APIs.", "required": [ "name", - "kind", - "network" + "kind" ], "properties": { "kind": { @@ -2219,10 +3363,6 @@ "name": { "type": "string", "description": "The name/identifier of the provider" - }, - "network": { - "type": "string", - "description": "The blockchain network (e.g., \"mainnet\", \"goerli\", \"polygon\")" } }, "additionalProperties": { @@ -2247,14 +3387,22 @@ }, "PruneResponse": { "type": "object", - "description": "Response payload for manifest pruning operation\n\nContains the count of successfully deleted orphaned manifests.", + "description": "Response for prune operation", "required": [ - "deleted_count" + "files_scheduled", + "gc_delay_secs" ], "properties": { - "deleted_count": { + "files_scheduled": { + "type": "integer", + "format": "int64", + "description": "Number of non-canonical files scheduled for garbage collection", + "minimum": 0 + }, + "gc_delay_secs": { "type": "integer", - "description": "Number of orphaned manifests successfully deleted", + "format": "int64", + "description": "Seconds before files become eligible for GC deletion", "minimum": 0 } } @@ -2311,6 +3459,223 @@ } } }, + "RegisterResponse": { + "type": "object", + "description": "Response payload for dataset registration", + "required": [ + "namespace", + "name", + "manifest_hash", + "kind", + "start_block", + "finalized_blocks_only", + "tables" + ], + "properties": { + "finalized_blocks_only": { + "type": "boolean", + "description": "Finalized blocks only" + }, + "kind": { + "type": "string", + "description": "Dataset kind" + }, + "manifest_hash": { + "type": "string", + "description": "Manifest hash" + }, + "name": { + "type": "string", + "description": "Dataset name" + }, + "namespace": { + "type": "string", + "description": "Dataset namespace" + }, + "start_block": { + "type": "integer", + "format": "int64", + "description": "Starting block", + "minimum": 0 + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tables" + }, + "version": { + "type": [ + "string", + "null" + ], + "description": "Version of the dataset, if provided during registration" + } + } + }, + "RestoreResponse": { + "type": "object", + "description": "Response for restore operation", + "required": [ + "total_files" + ], + "properties": { + "total_files": { + "type": "integer", + "format": "int32", + "description": "Total number of files restored" + } + } + }, + "RestoreTablePayload": { + "type": "object", + "description": "Optional request body for restore table operation", + "required": [ + "location_id" + ], + "properties": { + "location_id": { + "type": "integer", + "format": "int64", + "description": "Location ID of the revision to activate. If omitted, the latest\nrevision is discovered from object storage." + } + } + }, + "RestoredTableInfo": { + "type": "object", + "description": "Information about a restored physical table", + "required": [ + "table_name", + "location_id", + "url" + ], + "properties": { + "location_id": { + "type": "integer", + "format": "int64", + "description": "Unique location ID assigned in the metadata database" + }, + "table_name": { + "type": "string", + "description": "Name of the table within the dataset" + }, + "url": { + "type": "string", + "description": "Full URL to the storage location" + } + } + }, + "RevisionInfo": { + "type": "object", + "description": "Revision information returned by the API", + "required": [ + "id", + "path", + "active", + "metadata" + ], + "properties": { + "active": { + "type": "boolean", + "description": "Whether this revision is currently active" + }, + "id": { + "type": "integer", + "format": "int64", + "description": "Unique identifier for this revision (location ID)" + }, + "metadata": { + "$ref": "#/components/schemas/RevisionMetadataInfo", + "description": "Metadata about the revision" + }, + "path": { + "type": "string", + "description": "Relative path to the storage location" + }, + "writer": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Writer job ID responsible for populating this revision, if one exists" + } + } + }, + "RevisionMetadataInfo": { + "type": "object", + "description": "Revision metadata returned by the API", + "properties": { + "dataset_name": { + "type": "string", + "description": "Dataset name" + }, + "dataset_namespace": { + "type": "string", + "description": "Dataset namespace" + }, + "manifest_hash": { + "type": "string", + "description": "Manifest hash" + }, + "table_name": { + "type": "string", + "description": "Table name" + } + } + }, + "SchemaRequest": { + "type": "object", + "description": "Request for schema analysis with dependencies, tables, and functions", + "properties": { + "dependencies": { + "type": "object", + "description": "External dataset dependencies mapped by alias\n\nMaps alias names to dataset references (namespace/name@version or namespace/name@hash).\nThese aliases are used in SQL queries to reference external datasets.\nSymbolic references like \"latest\" or \"dev\" are not allowed.", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + }, + "functions": { + "type": "object", + "description": "User-defined function definitions mapped by function name\n\nMaps function names to their complete definitions including input/output types\nand implementation source code. These functions can be referenced in SQL queries\nas bare function calls (e.g., `my_function(args)` without dataset qualification).\n\nAt least one of `tables` or `functions` must be provided.\n\nFunction names must follow DataFusion UDF identifier rules:\n- Start with a letter (a-z, A-Z) or underscore (_)\n- Contain only letters, digits (0-9), underscores (_), and dollar signs ($)\n- Maximum length of 255 bytes", + "additionalProperties": {}, + "propertyNames": { + "type": "string" + } + }, + "tables": { + "type": "object", + "description": "Table definitions mapped by table name\n\nEach table is defined by a SQL query that may reference\ntables from dependencies using the alias names.", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + } + } + }, + "SchemaResponse": { + "type": "object", + "description": "Response returned by the schema endpoint\n\nContains inferred schemas for one or more tables.", + "required": [ + "schemas" + ], + "properties": { + "schemas": { + "type": "object", + "description": "Schemas for each table\n\nMaps table names to their inferred schemas.\nContains one entry per table definition.", + "additionalProperties": {}, + "propertyNames": { + "type": "string" + } + } + } + }, "SpecialTags": { "type": "object", "description": "Special tags pointing to versions or hashes", @@ -2341,6 +3706,57 @@ "Error" ] }, + "TableProgress": { + "type": "object", + "description": "Progress information for a single table", + "required": [ + "files_count", + "total_size_bytes" + ], + "properties": { + "current_block": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Highest block number that has been synced (null if no data yet)" + }, + "files_count": { + "type": "integer", + "format": "int64", + "description": "Number of Parquet files written for this table" + }, + "start_block": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Lowest block number that has been synced (null if no data yet)" + }, + "total_size_bytes": { + "type": "integer", + "format": "int64", + "description": "Total size of all Parquet files in bytes" + } + } + }, + "TruncateResponse": { + "type": "object", + "description": "Response for truncate operation", + "required": [ + "files_deleted" + ], + "properties": { + "files_deleted": { + "type": "integer", + "format": "int64", + "description": "Number of files deleted from object storage", + "minimum": 0 + } + } + }, "Value": {}, "VersionInfo": { "type": "object", @@ -2558,10 +3974,6 @@ "name": "jobs", "description": "Job management endpoints" }, - { - "name": "locations", - "description": "Location management endpoints" - }, { "name": "manifests", "description": "Manifest management endpoints" @@ -2578,9 +3990,13 @@ "name": "schema", "description": "Schema generation endpoints" }, + { + "name": "revisions", + "description": "Revision management endpoints" + }, { "name": "workers", "description": "Worker management endpoints" } ] -} \ No newline at end of file +} diff --git a/src/amp/admin/__init__.py b/src/amp/admin/__init__.py index 1238aa9..309f02e 100644 --- a/src/amp/admin/__init__.py +++ b/src/amp/admin/__init__.py @@ -13,13 +13,17 @@ from .datasets import DatasetsClient from .deployment import DeploymentContext from .errors import ( + ActivateRevisionError, AdminAPIError, CreateProviderError, DatabaseError, DatasetNotFoundError, + DeactivateRevisionError, DeleteLocationError, DeleteProviderError, + DeleteRevisionError, DependencyValidationError, + EventNotFoundError, FileNotFoundError, GetDatasetVersionError, GetFileInfoError, @@ -34,6 +38,7 @@ JobsDeleteError, JobStopError, ListAllDatasetsError, + ListAllManifestsError, ListDatasetVersionsError, ListJobsError, ListLocationFilesError, @@ -43,14 +48,21 @@ ManifestLinkingError, ManifestNotFoundError, ManifestRegistrationError, + ManifestValidationError, ProviderNotFoundError, + PruneError, + RestoreRevisionError, + RevisionNotFoundError, SchedulerError, StoreError, + TruncateError, UnlinkDatasetManifestsError, UnsupportedDatasetKindError, VersionTaggingError, + WorkerNotFoundError, ) from .jobs import JobsClient +from .revisions import RevisionsClient from .schema import SchemaClient __all__ = [ @@ -59,6 +71,7 @@ 'DatasetsClient', 'JobsClient', 'SchemaClient', + 'RevisionsClient', 'DeploymentContext', # Exceptions 'AdminAPIError', @@ -69,11 +82,13 @@ 'ManifestRegistrationError', 'ManifestLinkingError', 'ManifestNotFoundError', + 'ManifestValidationError', 'VersionTaggingError', 'UnsupportedDatasetKindError', 'StoreError', 'UnlinkDatasetManifestsError', 'ListAllDatasetsError', + 'ListAllManifestsError', 'ListDatasetVersionsError', 'GetDatasetVersionError', 'GetManifestError', @@ -94,6 +109,15 @@ 'ListProvidersError', 'DeleteProviderError', 'GetOutputSchemaError', + 'RevisionNotFoundError', + 'DeleteRevisionError', + 'PruneError', + 'TruncateError', + 'ActivateRevisionError', + 'DeactivateRevisionError', + 'RestoreRevisionError', + 'WorkerNotFoundError', + 'EventNotFoundError', 'InvalidPathError', 'DatabaseError', 'InternalServerError', diff --git a/src/amp/admin/client.py b/src/amp/admin/client.py index e6469c0..493c662 100644 --- a/src/amp/admin/client.py +++ b/src/amp/admin/client.py @@ -149,6 +149,28 @@ def schema(self): return SchemaClient(self) + @property + def revisions(self): + """Access revisions client. + + Returns: + RevisionsClient for table revision operations + """ + from .revisions import RevisionsClient + + return RevisionsClient(self) + + def list_manifests(self): + """List all manifests in the system. + + Returns: + ManifestsResponse with list of manifests + """ + from . import models + + response = self._request('GET', '/manifests') + return models.ManifestsResponse.model_validate(response.json()) + def close(self): """Close the HTTP client and release resources. diff --git a/src/amp/admin/datasets.py b/src/amp/admin/datasets.py index a195a65..581ce37 100644 --- a/src/amp/admin/datasets.py +++ b/src/amp/admin/datasets.py @@ -73,6 +73,9 @@ def deploy( revision: str, end_block: Optional[str] = None, parallelism: Optional[int] = None, + retry_strategy: Optional[dict] = None, + verify: Optional[bool] = None, + worker_id: Optional[str] = None, ) -> models.DeployResponse: """Deploy a dataset version. @@ -84,6 +87,9 @@ def deploy( revision: Version tag ('latest', 'dev', '1.0.0', etc.) end_block: Optional end block ('latest', '-100', '1000000', or null) parallelism: Optional number of parallel workers + retry_strategy: Optional retry strategy dict + verify: Optional flag to enable cryptographic verification of EVM block data + worker_id: Optional worker selector (exact ID or glob pattern) Returns: DeployResponse with job_id @@ -98,14 +104,15 @@ def deploy( """ path = f'/datasets/{namespace}/{name}/versions/{revision}/deploy' - # Build request body (POST requires JSON body, not query params) - body = {} - if end_block is not None: - body['end_block'] = end_block - if parallelism is not None: - body['parallelism'] = parallelism + request_data = models.DeployRequest( + end_block=end_block, + parallelism=parallelism, + retry_strategy=retry_strategy, + verify=verify, + worker_id=worker_id, + ) - response = self._admin._request('POST', path, json=body if body else {}) + response = self._admin._request('POST', path, json=request_data.model_dump(mode='json', exclude_none=True)) return models.DeployResponse.model_validate(response.json()) def list_all(self) -> models.DatasetsResponse: @@ -152,7 +159,7 @@ def get_versions(self, namespace: str, name: str) -> models.VersionsResponse: response = self._admin._request('GET', path) return models.VersionsResponse.model_validate(response.json()) - def get_version(self, namespace: str, name: str, revision: str) -> models.VersionInfo: + def get_version(self, namespace: str, name: str, revision: str) -> models.DatasetInfo: """Get detailed information about a specific dataset version. Args: @@ -161,7 +168,7 @@ def get_version(self, namespace: str, name: str, revision: str) -> models.Versio revision: Version tag or semantic version Returns: - VersionInfo with dataset details + DatasetInfo with dataset details Raises: DatasetNotFoundError: If dataset/version not found @@ -174,7 +181,7 @@ def get_version(self, namespace: str, name: str, revision: str) -> models.Versio """ path = f'/datasets/{namespace}/{name}/versions/{revision}' response = self._admin._request('GET', path) - return models.VersionInfo.model_validate(response.json()) + return models.DatasetInfo.model_validate(response.json()) def get_manifest(self, namespace: str, name: str, revision: str) -> dict: """Get the manifest for a specific dataset version. @@ -291,31 +298,88 @@ def delete(self, namespace: str, name: str) -> None: path = f'/datasets/{namespace}/{name}' self._admin._request('DELETE', path) - def get_sync_progress(self, namespace: str, name: str, revision: str = 'latest') -> models.SyncProgressResponse: - """Get sync progress for a dataset version. - - Returns per-table sync progress including current block numbers, - job status, and file statistics. This is useful for monitoring - the progress of data extraction jobs. + def list_jobs(self, namespace: str, name: str, revision: str) -> models.JobsResponse: + """List jobs for a specific dataset version. Args: namespace: Dataset namespace name: Dataset name - revision: Version tag or semantic version (default: 'latest') + revision: Version tag or semantic version Returns: - SyncProgressResponse with sync progress for all tables + JobsResponse with jobs for this dataset version Raises: DatasetNotFoundError: If dataset/version not found - GetSyncProgressError: If retrieval fails Example: - >>> client = AdminClient('http://localhost:8080') - >>> progress = client.datasets.get_sync_progress('_', 'eth_firehose', 'latest') - >>> for table in progress.tables: - ... print(f'{table.table_name}: block {table.current_block}, status: {table.job_status}') + >>> jobs = client.datasets.list_jobs('_', 'eth_firehose', 'latest') + >>> for job in jobs.jobs: + ... print(f'{job.id}: {job.status}') """ - path = f'/datasets/{namespace}/{name}/versions/{revision}/sync-progress' + path = f'/datasets/{namespace}/{name}/versions/{revision}/jobs' response = self._admin._request('GET', path) - return models.SyncProgressResponse.model_validate(response.json()) + return models.JobsResponse.model_validate(response.json()) + + def restore(self, namespace: str, name: str, revision: str) -> models.RestoreResponse: + """Restore physical tables for a dataset version. + + Args: + namespace: Dataset namespace + name: Dataset name + revision: Version tag or semantic version + + Returns: + RestoreResponse with number of files restored + + Raises: + DatasetNotFoundError: If dataset/version not found + + Example: + >>> result = client.datasets.restore('_', 'eth_firehose', 'latest') + >>> print(f'Restored {result.total_files} files') + """ + path = f'/datasets/{namespace}/{name}/versions/{revision}/restore' + response = self._admin._request('POST', path) + return models.RestoreResponse.model_validate(response.json()) + + def restore_table( + self, namespace: str, name: str, revision: str, table_name: str, location_id: Optional[int] = None + ) -> None: + """Restore a specific table for a dataset version. + + Args: + namespace: Dataset namespace + name: Dataset name + revision: Version tag or semantic version + table_name: Table to restore + location_id: Optional location ID of the revision to activate + + Raises: + DatasetNotFoundError: If dataset/version/table not found + + Example: + >>> client.datasets.restore_table('_', 'eth_firehose', 'latest', 'blocks') + """ + path = f'/datasets/{namespace}/{name}/versions/{revision}/tables/{table_name}/restore' + body = None + if location_id is not None: + body = models.RestoreTablePayload(location_id=location_id).model_dump(mode='json') + self._admin._request('POST', path, json=body) + + def delete_version(self, namespace: str, name: str, version: str) -> None: + """Delete a specific version of a dataset. + + Args: + namespace: Dataset namespace + name: Dataset name + version: Semantic version to delete (e.g., '1.0.0') + + Raises: + DatasetNotFoundError: If dataset/version not found + + Example: + >>> client.datasets.delete_version('_', 'my_dataset', '1.0.0') + """ + path = f'/datasets/{namespace}/{name}/versions/{version}' + self._admin._request('DELETE', path) diff --git a/src/amp/admin/errors.py b/src/amp/admin/errors.py index 2a2c1fe..44b81ef 100644 --- a/src/amp/admin/errors.py +++ b/src/amp/admin/errors.py @@ -219,6 +219,76 @@ class GetOutputSchemaError(AdminAPIError): pass +# Revision-related errors +class RevisionNotFoundError(AdminAPIError): + """Requested revision does not exist.""" + + pass + + +class DeleteRevisionError(AdminAPIError): + """Failed to delete revision.""" + + pass + + +class PruneError(AdminAPIError): + """Failed to prune revision.""" + + pass + + +class TruncateError(AdminAPIError): + """Failed to truncate revision.""" + + pass + + +class ActivateRevisionError(AdminAPIError): + """Failed to activate table revision.""" + + pass + + +class DeactivateRevisionError(AdminAPIError): + """Failed to deactivate table revision.""" + + pass + + +class RestoreRevisionError(AdminAPIError): + """Failed to restore table revision.""" + + pass + + +# Worker-related errors +class WorkerNotFoundError(AdminAPIError): + """Requested worker does not exist.""" + + pass + + +# Manifest-related errors +class ManifestValidationError(AdminAPIError): + """Manifest validation failed.""" + + pass + + +class ListAllManifestsError(AdminAPIError): + """Failed to list all manifests.""" + + pass + + +# Event-related errors +class EventNotFoundError(AdminAPIError): + """Requested event does not exist.""" + + pass + + # General errors class InvalidPathError(AdminAPIError): """Invalid path parameters.""" @@ -282,7 +352,7 @@ def map_error_response(status_code: int, error_data: dict) -> AdminAPIError: 'JOB_STOP_ERROR': JobStopError, 'JOB_DELETE_ERROR': JobDeleteError, 'JOBS_DELETE_ERROR': JobsDeleteError, - # Location errors + # Location errors (legacy) 'LOCATION_NOT_FOUND': LocationNotFoundError, 'LIST_LOCATIONS_ERROR': ListLocationsError, 'DELETE_LOCATION_ERROR': DeleteLocationError, @@ -297,8 +367,35 @@ def map_error_response(status_code: int, error_data: dict) -> AdminAPIError: 'DELETE_PROVIDER_ERROR': DeleteProviderError, # Schema errors 'GET_OUTPUT_SCHEMA_ERROR': GetOutputSchemaError, + # Revision errors + 'REVISION_NOT_FOUND': RevisionNotFoundError, + 'DELETE_REVISION_ERROR': DeleteRevisionError, + 'DELETE_TABLE_REVISION_ERROR': DeleteRevisionError, + 'PRUNE_ERROR': PruneError, + 'TRUNCATE_ERROR': TruncateError, + 'ACTIVATE_TABLE_REVISION_ERROR': ActivateRevisionError, + 'DEACTIVATE_TABLE_REVISION_ERROR': DeactivateRevisionError, + 'RESTORE_TABLE_REVISION_ERROR': RestoreRevisionError, + 'LIST_ALL_TABLE_REVISIONS_ERROR': ListLocationsError, + # Worker errors + 'WORKER_NOT_FOUND': WorkerNotFoundError, + # Manifest errors + 'MANIFEST_VALIDATION_ERROR': ManifestValidationError, + 'LIST_ALL_MANIFESTS_ERROR': ListAllManifestsError, + # Event errors + 'EVENT_NOT_FOUND': EventNotFoundError, + # Job errors (additional) + 'DELETE_JOBS_BY_STATUS_ERROR': JobsDeleteError, + 'STOP_JOB_ERROR': JobStopError, + 'GET_JOB_ERROR': JobNotFoundError, + 'GET_JOB_EVENTS_ERROR': ListJobsError, + 'GET_JOB_EVENT_ERROR': EventNotFoundError, # General errors 'INVALID_PATH': InvalidPathError, + 'INVALID_SELECTOR': InvalidPayloadError, + 'INVALID_QUERY_PARAMETERS': InvalidPayloadError, + 'INVALID_REQUEST_BODY': InvalidPayloadError, + 'METADATA_DB_ERROR': DatabaseError, 'DATABASE_ERROR': DatabaseError, 'INTERNAL_SERVER_ERROR': InternalServerError, } diff --git a/src/amp/admin/jobs.py b/src/amp/admin/jobs.py index 0fdecde..e0b033f 100644 --- a/src/amp/admin/jobs.py +++ b/src/amp/admin/jobs.py @@ -52,7 +52,6 @@ def get(self, job_id: int) -> models.JobInfo: Example: >>> job = client.jobs.get(123) >>> print(f'Status: {job.status}') - >>> print(f'Dataset: {job.dataset}') """ path = f'/jobs/{job_id}' response = self._admin._request('GET', path) @@ -88,6 +87,27 @@ def list(self, limit: int = 50, last_job_id: Optional[int] = None) -> models.Job response = self._admin._request('GET', '/jobs', params=params) return models.JobsResponse.model_validate(response.json()) + def create(self, request: models.CreateJobRequest) -> models.CreateJobResponse: + """Create a new job. + + Args: + request: Job creation request specifying job type and parameters + + Returns: + CreateJobResponse with the new job_id + + Raises: + SchedulerError: If job creation fails + + Example: + >>> from amp.admin.models import CreateJobRequest2, Kind1 + >>> request = CreateJobRequest2(kind=Kind1.materialize_raw) + >>> response = client.jobs.create(request) + >>> print(f'Job ID: {response.job_id}') + """ + response = self._admin._request('POST', '/jobs', json=request.model_dump(mode='json', exclude_none=True)) + return models.CreateJobResponse.model_validate(response.json()) + def wait_for_completion(self, job_id: int, poll_interval: int = 5, timeout: Optional[int] = None) -> models.JobInfo: """Poll job until completion or timeout. @@ -150,7 +170,7 @@ def stop(self, job_id: int) -> None: >>> client.jobs.stop(123) """ path = f'/jobs/{job_id}/stop' - self._admin._request('POST', path) + self._admin._request('PUT', path) def delete(self, job_id: int) -> None: """Delete a job in terminal state. @@ -170,18 +190,81 @@ def delete(self, job_id: int) -> None: path = f'/jobs/{job_id}' self._admin._request('DELETE', path) - def delete_many(self, job_ids: list[int]) -> None: - """Delete multiple jobs in bulk. + def delete_by_status(self, status: str) -> None: + """Delete all jobs matching a status filter. - All specified jobs must be in terminal states. + Args: + status: Status filter - one of 'Terminal', 'Completed', 'Stopped', 'Error' + + Raises: + JobsDeleteError: If deletion fails + + Example: + >>> client.jobs.delete_by_status('Completed') + """ + self._admin._request('DELETE', '/jobs', params={'status': status}) + + def get_events(self, job_id: int) -> models.JobEventsResponse: + """Get lifecycle events for a job. Args: - job_ids: List of job IDs to delete + job_id: Job ID + + Returns: + JobEventsResponse with list of events Raises: - JobsDeleteError: If any deletion fails + JobNotFoundError: If job not found Example: - >>> client.jobs.delete_many([123, 124, 125]) + >>> events = client.jobs.get_events(123) + >>> for event in events.events: + ... print(f'{event.event_type} at {event.created_at}') """ - self._admin._request('DELETE', '/jobs', json={'job_ids': job_ids}) + path = f'/jobs/{job_id}/events' + response = self._admin._request('GET', path) + return models.JobEventsResponse.model_validate(response.json()) + + def get_event(self, job_id: int, event_id: int) -> models.JobEventDetailResponse: + """Get a specific lifecycle event for a job. + + Args: + job_id: Job ID + event_id: Event ID + + Returns: + JobEventDetailResponse with event details + + Raises: + JobNotFoundError: If job or event not found + + Example: + >>> event = client.jobs.get_event(123, 1) + >>> print(f'{event.event_type}: {event.detail}') + """ + path = f'/jobs/{job_id}/events/{event_id}' + response = self._admin._request('GET', path) + return models.JobEventDetailResponse.model_validate(response.json()) + + def get_progress(self, job_id: int) -> models.JobProgressResponse: + """Get progress information for a job. + + Returns per-table progress including current block numbers and file statistics. + + Args: + job_id: Job ID + + Returns: + JobProgressResponse with per-table progress + + Raises: + JobNotFoundError: If job not found + + Example: + >>> progress = client.jobs.get_progress(123) + >>> for table, info in progress.tables.items(): + ... print(f'{table}: block {info.current_block}') + """ + path = f'/jobs/{job_id}/progress' + response = self._admin._request('GET', path) + return models.JobProgressResponse.model_validate(response.json()) diff --git a/src/amp/admin/models.py b/src/amp/admin/models.py index e7e1745..7ce8cc9 100644 --- a/src/amp/admin/models.py +++ b/src/amp/admin/models.py @@ -1,14 +1,138 @@ # generated by datamodel-codegen: # filename: admin.spec.json -# timestamp: 2025-11-06T23:57:02+00:00 from __future__ import annotations -from datetime import datetime from enum import Enum from typing import Annotated, Any, Optional, Union -from pydantic import BaseModel, Field +from pydantic import AwareDatetime, BaseModel, Field, RootModel + + +class ActivationPayload(BaseModel): + """ + Payload for activating a table revision + """ + + dataset: str + """ + Dataset reference + """ + table_name: str + """ + Table name + """ + + +class Kind(Enum): + gc = 'gc' + + +class CreateJobRequest1(BaseModel): + """ + Schedule a garbage collection job for a physical table revision. + """ + + retry_strategy: Optional[dict[str, Any]] = None + """ + Optional retry strategy controlling how failed jobs are retried. + """ + worker_id: Optional[str] = None + """ + Optional worker selector (exact ID or glob pattern). + """ + kind: Kind + + +class Kind1(Enum): + materialize_raw = 'materialize-raw' + + +class CreateJobRequest2(BaseModel): + """ + Schedule a raw dataset materialization job. + """ + + retry_strategy: Optional[dict[str, Any]] = None + """ + Optional retry strategy controlling how failed jobs are retried. + """ + worker_id: Optional[str] = None + """ + Optional worker selector (exact ID or glob pattern). + """ + kind: Kind1 + + +class Kind2(Enum): + materialize_derived = 'materialize-derived' + + +class CreateJobRequest3(BaseModel): + """ + Schedule a derived dataset materialization job. + """ + + retry_strategy: Optional[dict[str, Any]] = None + """ + Optional retry strategy controlling how failed jobs are retried. + """ + worker_id: Optional[str] = None + """ + Optional worker selector (exact ID or glob pattern). + """ + kind: Kind2 + + +class CreateJobRequest(RootModel[Union[CreateJobRequest1, CreateJobRequest2, CreateJobRequest3]]): + root: Union[CreateJobRequest1, CreateJobRequest2, CreateJobRequest3] + """ + Request body for creating a job. + + Dispatches on the `kind` field to determine the job type. + Fields for each variant are defined by the corresponding job descriptor type. + """ + + +class CreateJobResponse(BaseModel): + """ + Response body for a created job. + """ + + job_id: int + """ + The ID of the scheduled job. + """ + + +class CreatePayload(BaseModel): + """ + Payload for creating a table revision + """ + + dataset: str + """ + Dataset reference + """ + path: str + """ + Revision path in object storage + """ + table_name: str + """ + Table name + """ + + +class CreateRevisionResponse(BaseModel): + """ + Response for creating a table revision + """ + + location_id: int + """ + Location ID assigned to the new revision + """ class Dataset(BaseModel): @@ -37,6 +161,10 @@ class DatasetInfo(BaseModel): Detailed dataset information """ + finalized_blocks_only: bool + """ + Finalized blocks only + """ kind: str """ Dataset kind @@ -57,6 +185,14 @@ class DatasetInfo(BaseModel): """ Revision requested """ + start_block: Annotated[int, Field(ge=0)] + """ + Starting block + """ + tables: list[str] + """ + Tables + """ class DatasetSummary(BaseModel): @@ -93,6 +229,21 @@ class DatasetsResponse(BaseModel): """ +class DeactivationPayload(BaseModel): + """ + Payload for deactivating a table revision + """ + + dataset: str + """ + Dataset reference + """ + table_name: str + """ + Table name + """ + + class DeployResponse(BaseModel): """ Response for deploy operation @@ -104,7 +255,8 @@ class DeployResponse(BaseModel): """ -class EndBlock(BaseModel): +class EndBlock(RootModel[Optional[str]]): + root: Optional[str] """ End block configuration for API requests. @@ -114,14 +266,9 @@ class EndBlock(BaseModel): - `null` (or omitted): Continuous dumping - never stops, keeps extracting new blocks as they arrive - `"latest"`: Stop at the latest available block at the time the dump starts - A positive number as a string (e.g., `"1000000"`): Stop at the specified absolute block number - - A negative number as a string (e.g., `"-100"`): Stop at (latest block - N), useful for staying N - blocks behind the chain tip - - Note: This is a simple wrapper around Optional[str] for documentation purposes. + - A negative number as a string (e.g., `"-100"`): Stop at (latest block - N), useful for staying N blocks behind the chain tip """ - value: Optional[str] = None - class ErrorResponse(BaseModel): """ @@ -205,171 +352,114 @@ class FileInfo(BaseModel): """ -class FileListInfo(BaseModel): +class JobEventDetailResponse(BaseModel): """ - Minimal file information for location file listings - - This struct represents essential file metadata for list endpoints, - containing only the most relevant information needed for file browsing - within a location context. + Response body for GET /jobs/{id}/events/{event_id} endpoint. """ - file_name: str - """ - Name of the file (e.g., "blocks_0000000000_0000099999.parquet") - """ - id: int - """ - Unique identifier for this file (64-bit integer) - """ - object_size: Optional[int] = None + created_at: str """ - Size of the file object in bytes + Event timestamp in ISO 8601 / RFC 3339 format """ - - -class JobInfo(BaseModel): + detail: Optional[Any] = None """ - Job information returned by the API - - This struct represents job metadata in a format suitable for API responses. - It contains essential information about a job without exposing internal - database implementation details. + Optional structured detail payload """ - - descriptor: Any + event_type: str """ - Job descriptor containing job-specific parameters as JSON + Event type (e.g., SCHEDULED, RUNNING, COMPLETED, ERROR, FATAL, STOPPED) """ id: int """ - Unique identifier for this job (64-bit integer) + Event ID """ - node_id: str + job_id: int """ - ID of the worker node this job is scheduled for + Job ID """ - status: str + node_id: str """ - Current status of the job (Scheduled, Running, Completed, Stopped, Failed, etc.) + ID of the worker node that recorded this event """ -class JobsResponse(BaseModel): +class JobEventInfo(BaseModel): """ - API response containing job information + A single job lifecycle event. """ - jobs: list[JobInfo] + created_at: str """ - List of jobs + Event timestamp in ISO 8601 / RFC 3339 format """ - next_cursor: Optional[int] = None + event_type: str """ - Cursor for the next page of results (None if no more results) + Event type (e.g., SCHEDULED, RUNNING, COMPLETED, ERROR, FATAL, STOPPED) """ - - -class LocationFilesResponse(BaseModel): - """ - Collection response for location file listings - - This response structure provides paginated file data with - cursor-based pagination support for efficient traversal. - """ - - files: list[FileListInfo] + id: int """ - List of files in this page with minimal information + Event ID """ - next_cursor: Optional[int] = None + node_id: str """ - Cursor for the next page of results - use as last_file_id in next request (None if no more results) + ID of the worker node that recorded this event """ -class LocationInfo(BaseModel): +class JobEventsResponse(BaseModel): """ - Location information returned by the API - - This struct represents location metadata from the database in a format - suitable for API responses. It contains all the essential information - about where dataset table data is stored. + Response body for GET /jobs/{id}/events endpoint. """ - active: bool - """ - Whether this location is currently active for queries + events: list[JobEventInfo] """ - dataset: str - """ - Name of the dataset this location belongs to - """ - dataset_version: str - """ - Version of the dataset using semantic versioning (e.g., "1.0.0", or empty string for unversioned) - """ - id: int - """ - Unique identifier for this location (64-bit integer) - """ - table: str - """ - Name of the table within the dataset (e.g., "blocks", "transactions") - """ - url: str + List of lifecycle events """ - Full URL to the storage location (e.g., "s3://bucket/path/table.parquet", "file:///local/path/table.parquet") - """ - writer: Optional[int] = None + job_id: int """ - Writer job ID (64-bit integer, if one exists) + Job ID """ -class LocationInfoWithDetails(BaseModel): +class JobInfo(BaseModel): """ - Location information with writer job details + Represents job information for the API response """ - active: bool + created_at: str """ - Whether this location is currently active for queries + Job creation timestamp in ISO 8601 / RFC 3339 format """ - dataset: str + descriptor: Any """ - Name of the dataset this location belongs to + Job descriptor containing job-specific parameters as JSON """ - dataset_version: str + id: int """ - Version of the dataset using semantic versioning (e.g., "1.0.0", or empty string for unversioned) + Unique identifier for the job (64-bit integer) """ - id: int + node_id: str """ - Unique identifier for this location (64-bit integer) + ID of the worker node this job is scheduled for """ - table: str + status: str """ - Name of the table within the dataset (e.g., "blocks", "transactions") + Current status of the job (Scheduled, Running, Completed, Stopped, Failed, etc.) """ - url: str + updated_at: str """ - Full URL to the storage location (e.g., "s3://bucket/path/table.parquet", "file:///local/path/table.parquet") + Job last update timestamp in ISO 8601 / RFC 3339 format """ - writer: Optional[JobInfo] = None -class LocationsResponse(BaseModel): +class JobsResponse(BaseModel): """ - API response containing location information - - This response structure provides paginated location data with - cursor-based pagination support for efficient traversal. + API response containing job information """ - locations: list[LocationInfo] + jobs: list[JobInfo] """ - List of locations in this page + List of jobs """ next_cursor: Optional[int] = None """ @@ -392,52 +482,39 @@ class ManifestDatasetsResponse(BaseModel): """ -class ManifestResponse(BaseModel): +class ManifestInfo(BaseModel): """ - Response wrapper for manifest content + Summary information for a single manifest """ - -class OutputSchemaRequest(BaseModel): + dataset_count: Annotated[int, Field(ge=0)] """ - Request payload for output schema analysis - - Contains the SQL query to analyze and optional configuration flags. + Number of datasets using this manifest """ - - is_sql_dataset: Optional[bool] = None + hash: str """ - Whether this is a SQL dataset (affects block number field inclusion) - - When true, a special block number field is prepended to the schema. - This field tracks the block number for each row in SQL datasets. + Content-addressable hash (SHA-256) """ - sql_query: str + kind: str """ - The SQL query to analyze for output schema determination + Dataset kind (e.g. "evm-rpc", "solana", "firehose", "manifest") """ -class OutputSchemaResponse(BaseModel): +class ManifestResponse(BaseModel): """ - Response returned by the output schema endpoint - - Contains the determined schema and list of networks referenced by the query. + Response wrapper for manifest content """ - networks: list[str] - """ - List of networks referenced by the query - Contains the network names of all datasets/tables referenced - in the SQL query (e.g., "mainnet", "polygon", etc.). +class ManifestsResponse(BaseModel): """ - schema_: Annotated[Any, Field(alias='schema')] + Response for listing all manifests """ - The output schema for the SQL query - Describes the structure and types of columns that will be returned - when executing the provided SQL query against the dataset. + manifests: list[ManifestInfo] + """ + List of all manifests in the system """ @@ -464,10 +541,6 @@ class ProviderInfo(BaseModel): """ The name/identifier of the provider """ - network: str - """ - The blockchain network (e.g., "mainnet", "goerli", "polygon") - """ class ProvidersResponse(BaseModel): @@ -486,14 +559,16 @@ class ProvidersResponse(BaseModel): class PruneResponse(BaseModel): """ - Response payload for manifest pruning operation - - Contains the count of successfully deleted orphaned manifests. + Response for prune operation """ - deleted_count: Annotated[int, Field(ge=0)] + files_scheduled: Annotated[int, Field(ge=0)] """ - Number of orphaned manifests successfully deleted + Number of non-canonical files scheduled for garbage collection + """ + gc_delay_secs: Annotated[int, Field(ge=0)] + """ + Seconds before files become eligible for GC deletion """ @@ -510,13 +585,12 @@ class RegisterManifestResponse(BaseModel): """ -class Manifest(BaseModel): +class Manifest(RootModel[str]): + root: Annotated[str, Field(max_length=64, min_length=64, pattern='[0-9a-fA-F]{64}')] """ A manifest hash (64-character SHA-256 hex string) """ - hash: Annotated[str, Field(max_length=64, min_length=64, pattern='[0-9a-fA-F]{64}')] - class RegisterRequest(BaseModel): """ @@ -549,6 +623,163 @@ class RegisterRequest(BaseModel): """ +class RegisterResponse(BaseModel): + """ + Response payload for dataset registration + """ + + finalized_blocks_only: bool + """ + Finalized blocks only + """ + kind: str + """ + Dataset kind + """ + manifest_hash: str + """ + Manifest hash + """ + name: str + """ + Dataset name + """ + namespace: str + """ + Dataset namespace + """ + start_block: Annotated[int, Field(ge=0)] + """ + Starting block + """ + tables: list[str] + """ + Tables + """ + version: Optional[str] = None + """ + Version of the dataset, if provided during registration + """ + + +class RestoreResponse(BaseModel): + """ + Response for restore operation + """ + + total_files: int + """ + Total number of files restored + """ + + +class RestoreTablePayload(BaseModel): + """ + Optional request body for restore table operation + """ + + location_id: int + """ + Location ID of the revision to activate. If omitted, the latest + revision is discovered from object storage. + """ + + +class RestoredTableInfo(BaseModel): + """ + Information about a restored physical table + """ + + location_id: int + """ + Unique location ID assigned in the metadata database + """ + table_name: str + """ + Name of the table within the dataset + """ + url: str + """ + Full URL to the storage location + """ + + +class RevisionMetadataInfo(BaseModel): + """ + Revision metadata returned by the API + """ + + dataset_name: Optional[str] = None + """ + Dataset name + """ + dataset_namespace: Optional[str] = None + """ + Dataset namespace + """ + manifest_hash: Optional[str] = None + """ + Manifest hash + """ + table_name: Optional[str] = None + """ + Table name + """ + + +class SchemaRequest(BaseModel): + """ + Request for schema analysis with dependencies, tables, and functions + """ + + dependencies: Optional[dict[str, str]] = None + """ + External dataset dependencies mapped by alias + + Maps alias names to dataset references (namespace/name@version or namespace/name@hash). + These aliases are used in SQL queries to reference external datasets. + Symbolic references like "latest" or "dev" are not allowed. + """ + functions: Optional[dict[str, Any]] = None + """ + User-defined function definitions mapped by function name + + Maps function names to their complete definitions including input/output types + and implementation source code. These functions can be referenced in SQL queries + as bare function calls (e.g., `my_function(args)` without dataset qualification). + + At least one of `tables` or `functions` must be provided. + + Function names must follow DataFusion UDF identifier rules: + - Start with a letter (a-z, A-Z) or underscore (_) + - Contain only letters, digits (0-9), underscores (_), and dollar signs ($) + - Maximum length of 255 bytes + """ + tables: Optional[dict[str, str]] = None + """ + Table definitions mapped by table name + + Each table is defined by a SQL query that may reference + tables from dependencies using the alias names. + """ + + +class SchemaResponse(BaseModel): + """ + Response returned by the schema endpoint + + Contains inferred schemas for one or more tables. + """ + + schemas: dict[str, Any] + """ + Schemas for each table + + Maps table names to their inferred schemas. + Contains one entry per table definition. + """ + + class SpecialTags(BaseModel): """ Special tags pointing to versions or hashes @@ -575,10 +806,42 @@ class String(Enum): Error = 'Error' -class Value(BaseModel): - """Generic value wrapper for Any type""" +class TableProgress(BaseModel): + """ + Progress information for a single table + """ - value: Any + current_block: Optional[int] = None + """ + Highest block number that has been synced (null if no data yet) + """ + files_count: int + """ + Number of Parquet files written for this table + """ + start_block: Optional[int] = None + """ + Lowest block number that has been synced (null if no data yet) + """ + total_size_bytes: int + """ + Total size of all Parquet files in bytes + """ + + +class TruncateResponse(BaseModel): + """ + Response for truncate operation + """ + + files_deleted: Annotated[int, Field(ge=0)] + """ + Number of files deleted from object storage + """ + + +class Value(RootModel[Any]): + root: Any class VersionInfo(BaseModel): @@ -635,7 +898,7 @@ class WorkerInfo(BaseModel): This is a lightweight summary view suitable for list endpoints. """ - heartbeat_at: Annotated[datetime, Field(examples=['2025-01-15T17:20:15.456789Z'])] + heartbeat_at: Annotated[AwareDatetime, Field(examples=['2025-01-15T17:20:15.456789Z'])] """ Last heartbeat timestamp (RFC3339 format) @@ -674,7 +937,7 @@ class WorkerMetadata(BaseModel): """ build_date: Annotated[ - datetime, + AwareDatetime, Field(examples=['2025-01-15T15:45:30Z', '2025-01-15T10:45:30-05:00', 'unknown']), ] """ @@ -695,7 +958,7 @@ class WorkerMetadata(BaseModel): Returns "unknown" if commit information is not available. """ commit_timestamp: Annotated[ - datetime, + AwareDatetime, Field(examples=['2025-01-15T14:30:00Z', '2025-01-15T09:30:00-05:00', 'unknown']), ] """ @@ -775,67 +1038,88 @@ class DeployRequest(BaseModel): Defaults to 1 if not specified. """ + retry_strategy: Optional[dict[str, Any]] = None + """ + Optional retry strategy controlling how failed jobs are retried. + Supports three strategies: + - `none`: Never retry — fail immediately on first error. + - `bounded`: Retry up to `max_attempts` times with configurable backoff. + - `unless_stopped`: Retry indefinitely until the job is explicitly stopped. -class TableSyncProgress(BaseModel): + If not specified, the scheduler applies its default strategy. """ - Sync progress information for a single table + verify: Optional[bool] = None """ + Enable cryptographic verification of EVM block data during extraction. - table_name: str + When enabled, verifies block hashes, transaction roots, and receipt roots + before writing data to storage. Only applicable to EVM raw datasets. + Verification failures are retryable errors. + + Defaults to false if not specified. """ - Name of the table within the dataset + worker_id: Optional[str] = None """ - current_block: Optional[int] = None + Optional worker selector - either an exact worker ID or a glob pattern. + + Examples: + - `"worker-node-0"` - assigns to the specific worker with ID "worker-node-0" + - `"worker-eth-*"` - randomly selects from workers matching the pattern + + If not specified, a worker will be selected randomly from all available workers. + If a glob pattern is provided, one matching worker will be randomly selected + The worker must be active (has sent heartbeats recently) for the deployment to succeed. """ - Highest block number that has been synced (null if no data yet) + + +class JobProgressResponse(BaseModel): """ - start_block: Optional[int] = None + API response containing progress information for a job """ - Lowest block number that has been synced (null if no data yet) + + detail: Optional[Any] = None """ - job_id: Optional[int] = None + Structured error detail (present when job is in error/fatal state) """ - ID of the writer job (null if no active job) + job_id: int """ - job_status: Optional[str] = None + Job ID """ - Status of the writer job (null if no active job) + job_status: str """ - files_count: int + Current job status """ - Number of Parquet files written for this table + tables: dict[str, TableProgress] """ - total_size_bytes: int - """ - Total size of all Parquet files in bytes + Progress for each table written by this job, keyed by table name """ -class SyncProgressResponse(BaseModel): +class RevisionInfo(BaseModel): """ - API response containing sync progress information for a dataset + Revision information returned by the API """ - dataset_namespace: str + active: bool """ - Dataset namespace + Whether this revision is currently active """ - dataset_name: str + id: int """ - Dataset name + Unique identifier for this revision (location ID) """ - revision: str + metadata: RevisionMetadataInfo """ - Requested revision + Metadata about the revision """ - manifest_hash: str + path: str """ - Resolved manifest hash + Relative path to the storage location """ - tables: list[TableSyncProgress] + writer: Optional[int] = None """ - Sync progress for each table in the dataset + Writer job ID responsible for populating this revision, if one exists """ @@ -848,14 +1132,14 @@ class WorkerDetailResponse(BaseModel): worker health, version tracking, and operational status. """ - created_at: Annotated[datetime, Field(examples=['2025-01-15T14:30:00.123456Z'])] + created_at: Annotated[AwareDatetime, Field(examples=['2025-01-15T14:30:00.123456Z'])] """ Timestamp when the worker was first created in the system (RFC3339 format) The initial registration time of this worker. This timestamp never changes and represents when the worker first appeared in the system. """ - heartbeat_at: Annotated[datetime, Field(examples=['2025-01-15T17:20:15.456789Z'])] + heartbeat_at: Annotated[AwareDatetime, Field(examples=['2025-01-15T17:20:15.456789Z'])] """ Last heartbeat timestamp (RFC3339 format) @@ -890,7 +1174,7 @@ class WorkerDetailResponse(BaseModel): Must start with a letter and contain only alphanumeric characters, underscores, hyphens, and dots. """ - registered_at: Annotated[datetime, Field(examples=['2025-01-15T16:45:30.789012Z'])] + registered_at: Annotated[AwareDatetime, Field(examples=['2025-01-15T16:45:30.789012Z'])] """ Timestamp when the worker last registered (RFC3339 format) diff --git a/src/amp/admin/revisions.py b/src/amp/admin/revisions.py new file mode 100644 index 0000000..f55de93 --- /dev/null +++ b/src/amp/admin/revisions.py @@ -0,0 +1,214 @@ +"""Revisions client for Admin API. + +This module provides the RevisionsClient class for managing physical +table revisions (storage locations). +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Optional + +from . import models + +if TYPE_CHECKING: + from .client import AdminClient + + +class RevisionsClient: + """Client for revision operations. + + Provides methods for managing physical table revisions, including + listing, creating, activating, deactivating, pruning, and truncating. + + Args: + admin_client: Parent AdminClient instance + + Example: + >>> client = AdminClient('http://localhost:8080') + >>> revisions = client.revisions.list() + """ + + def __init__(self, admin_client: 'AdminClient'): + """Initialize revisions client. + + Args: + admin_client: Parent AdminClient instance + """ + self._admin = admin_client + + def list( + self, + active: Optional[bool] = None, + limit: Optional[int] = None, + last_id: Optional[int] = None, + ) -> list[models.RevisionInfo]: + """List table revisions. + + Args: + active: Filter by active status + limit: Maximum number of revisions to return (default: 100) + last_id: Cursor for pagination + + Returns: + List of RevisionInfo + + Example: + >>> revisions = client.revisions.list(active=True, limit=50) + >>> for rev in revisions: + ... print(f'{rev.id}: {rev.path} (active={rev.active})') + """ + params = {} + if active is not None: + params['active'] = active + if limit is not None: + params['limit'] = limit + if last_id is not None: + params['last_id'] = last_id + + response = self._admin._request('GET', '/revisions', params=params) + return [models.RevisionInfo.model_validate(item) for item in response.json()] + + def get(self, revision_id: int) -> models.RevisionInfo: + """Get a specific revision by ID. + + Args: + revision_id: Revision (location) ID + + Returns: + RevisionInfo with revision details + + Example: + >>> rev = client.revisions.get(42) + >>> print(f'Path: {rev.path}, Active: {rev.active}') + """ + path = f'/revisions/{revision_id}' + response = self._admin._request('GET', path) + return models.RevisionInfo.model_validate(response.json()) + + def create(self, dataset: str, table_name: str, storage_path: str) -> models.CreateRevisionResponse: + """Create a new table revision. + + Args: + dataset: Dataset reference + table_name: Table name + storage_path: Revision path in object storage + + Returns: + CreateRevisionResponse with location_id + + Example: + >>> result = client.revisions.create('_/eth_firehose@0.0.0', 'blocks', 's3://bucket/path') + >>> print(f'Location ID: {result.location_id}') + """ + request_data = models.CreatePayload(dataset=dataset, table_name=table_name, path=storage_path) + response = self._admin._request('POST', '/revisions', json=request_data.model_dump(mode='json')) + return models.CreateRevisionResponse.model_validate(response.json()) + + def delete(self, revision_id: int) -> None: + """Delete a revision. + + Args: + revision_id: Revision (location) ID + + Example: + >>> client.revisions.delete(42) + """ + path = f'/revisions/{revision_id}' + self._admin._request('DELETE', path) + + def prune( + self, + revision_id: int, + before_block: Optional[int] = None, + gc_delay_secs: Optional[int] = None, + ) -> models.PruneResponse: + """Prune non-canonical files from a revision. + + Args: + revision_id: Revision (location) ID + before_block: Only prune files before this block number + gc_delay_secs: Seconds before files become eligible for GC deletion + + Returns: + PruneResponse with files_scheduled and gc_delay_secs + + Example: + >>> result = client.revisions.prune(42) + >>> print(f'Scheduled {result.files_scheduled} files for GC') + """ + path = f'/revisions/{revision_id}/prune' + params = {} + if before_block is not None: + params['before_block'] = before_block + if gc_delay_secs is not None: + params['gc_delay_secs'] = gc_delay_secs + + response = self._admin._request('DELETE', path, params=params) + return models.PruneResponse.model_validate(response.json()) + + def truncate(self, revision_id: int, concurrency: Optional[int] = None) -> models.TruncateResponse: + """Truncate all files from a revision. + + Args: + revision_id: Revision (location) ID + concurrency: Optional concurrency for deletion + + Returns: + TruncateResponse with files_deleted count + + Example: + >>> result = client.revisions.truncate(42) + >>> print(f'Deleted {result.files_deleted} files') + """ + path = f'/revisions/{revision_id}/truncate' + params = {} + if concurrency is not None: + params['concurrency'] = concurrency + + response = self._admin._request('DELETE', path, params=params) + return models.TruncateResponse.model_validate(response.json()) + + def activate(self, revision_id: int, dataset: str, table_name: str) -> None: + """Activate a table revision. + + Args: + revision_id: Revision (location) ID + dataset: Dataset reference + table_name: Table name + + Example: + >>> client.revisions.activate(42, '_/eth_firehose@0.0.0', 'blocks') + """ + path = f'/revisions/{revision_id}/activate' + request_data = models.ActivationPayload(dataset=dataset, table_name=table_name) + self._admin._request('POST', path, json=request_data.model_dump(mode='json')) + + def deactivate(self, dataset: str, table_name: str) -> None: + """Deactivate a table revision. + + Args: + dataset: Dataset reference + table_name: Table name + + Example: + >>> client.revisions.deactivate('_/eth_firehose@0.0.0', 'blocks') + """ + request_data = models.DeactivationPayload(dataset=dataset, table_name=table_name) + self._admin._request('POST', '/revisions/deactivate', json=request_data.model_dump(mode='json')) + + def restore(self, revision_id: int) -> models.RestoreResponse: + """Restore files for a revision. + + Args: + revision_id: Revision (location) ID + + Returns: + RestoreResponse with total_files restored + + Example: + >>> result = client.revisions.restore(42) + >>> print(f'Restored {result.total_files} files') + """ + path = f'/revisions/{revision_id}/restore' + response = self._admin._request('POST', path) + return models.RestoreResponse.model_validate(response.json()) diff --git a/src/amp/admin/schema.py b/src/amp/admin/schema.py index 01bcf87..568fce9 100644 --- a/src/amp/admin/schema.py +++ b/src/amp/admin/schema.py @@ -1,10 +1,10 @@ """Schema client for Admin API. -This module provides the SchemaClient class for querying output schemas -of SQL queries without executing them. +This module provides the SchemaClient class for analyzing schemas +of dataset tables and functions. """ -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Optional from . import models @@ -15,15 +15,19 @@ class SchemaClient: """Client for schema operations. - Provides methods for validating SQL queries and determining output schemas - using DataFusion's query planner. + Provides methods for analyzing dataset schemas by validating SQL queries + and inferring output schemas using DataFusion's query planner. Args: admin_client: Parent AdminClient instance Example: >>> client = AdminClient('http://localhost:8080') - >>> schema = client.schema.get_output_schema('SELECT * FROM eth.blocks', True) + >>> response = client.schema.analyze( + ... dependencies={'eth': '_/eth_firehose@0.0.0'}, + ... tables={'blocks': 'SELECT block_num, hash FROM eth.blocks'}, + ... ) + >>> print(response.schemas) """ def __init__(self, admin_client: 'AdminClient'): @@ -34,31 +38,43 @@ def __init__(self, admin_client: 'AdminClient'): """ self._admin = admin_client - def get_output_schema(self, sql_query: str, is_sql_dataset: bool = True) -> models.OutputSchemaResponse: - """Get output schema for a SQL query. + def analyze( + self, + dependencies: Optional[dict[str, str]] = None, + functions: Optional[dict[str, Any]] = None, + tables: Optional[dict[str, str]] = None, + ) -> models.SchemaResponse: + """Analyze schemas for tables and functions. - Validates the query and returns the Arrow schema that would be produced, - without actually executing the query. + Validates SQL queries and infers output schemas without executing them. + At least one of tables or functions must be provided. Args: - sql_query: SQL query to analyze - is_sql_dataset: Whether this is for a SQL dataset (default: True) + dependencies: External dataset dependencies mapped by alias + (e.g., {'eth': '_/eth_firehose@0.0.0'}) + functions: User-defined function definitions mapped by name + tables: Table definitions as SQL queries mapped by table name + (e.g., {'blocks': 'SELECT block_num FROM eth.blocks'}) Returns: - OutputSchemaResponse with Arrow schema + SchemaResponse with inferred schemas for each table/function Raises: GetOutputSchemaError: If schema analysis fails - DependencyValidationError: If query references invalid dependencies + DependencyValidationError: If dependencies are invalid Example: - >>> schema_resp = client.schema.get_output_schema( - ... 'SELECT block_num, hash FROM eth.blocks WHERE block_num > 1000000', - ... is_sql_dataset=True + >>> response = client.schema.analyze( + ... dependencies={'eth': '_/eth_firehose@0.0.0'}, + ... tables={'blocks': 'SELECT block_num, hash FROM eth.blocks'}, ... ) - >>> print(schema_resp.schema) + >>> print(response.schemas['blocks']) """ - request_data = models.OutputSchemaRequest(sql_query=sql_query, is_sql_dataset=is_sql_dataset) - - response = self._admin._request('POST', '/schema', json=request_data.model_dump(mode='json')) - return models.OutputSchemaResponse.model_validate(response.json()) + request_data = models.SchemaRequest( + dependencies=dependencies, + functions=functions, + tables=tables, + ) + + response = self._admin._request('POST', '/schema', json=request_data.model_dump(mode='json', exclude_none=True)) + return models.SchemaResponse.model_validate(response.json()) diff --git a/src/amp/client.py b/src/amp/client.py index 2eee462..abadeaf 100644 --- a/src/amp/client.py +++ b/src/amp/client.py @@ -200,8 +200,11 @@ def to_manifest(self, table_name: str, network: str = 'mainnet') -> dict: >>> print(manifest['kind']) 'manifest' """ - # Get schema from Admin API - schema_response = self.client.schema.get_output_schema(self.query, is_sql_dataset=True) + # Get schema from Admin API using the new schema endpoint + schema_response = self.client.schema.analyze( + dependencies=self._dependencies if self._dependencies else None, + tables={table_name: self.query}, + ) # Build manifest structure matching tests/config/manifests/*.json format manifest = { @@ -210,7 +213,7 @@ def to_manifest(self, table_name: str, network: str = 'mainnet') -> dict: 'tables': { table_name: { 'input': {'sql': self.query}, - 'schema': schema_response.schema_, # Use schema_ field (schema is aliased in Pydantic) + 'schema': schema_response.schemas.get(table_name, {}), 'network': network, } }, diff --git a/tests/integration/admin/test_admin_client.py b/tests/integration/admin/test_admin_client.py index 82e7648..b5e1695 100644 --- a/tests/integration/admin/test_admin_client.py +++ b/tests/integration/admin/test_admin_client.py @@ -96,3 +96,28 @@ def test_schema_property(self): assert schema_client is not None assert schema_client._admin is client + + @respx.mock + def test_revisions_property(self): + """Test accessing revisions client via property.""" + client = AdminClient('http://localhost:8080') + revisions_client = client.revisions + + assert revisions_client is not None + assert revisions_client._admin is client + + @respx.mock + def test_list_manifests(self): + """Test listing manifests.""" + manifests_response = { + 'manifests': [ + {'hash': 'abc123' + '0' * 58, 'kind': 'manifest', 'dataset_count': 2}, + ] + } + respx.get('http://localhost:8080/manifests').mock(return_value=Response(200, json=manifests_response)) + + client = AdminClient('http://localhost:8080') + response = client.list_manifests() + + assert len(response.manifests) == 1 + assert response.manifests[0].kind == 'manifest' diff --git a/tests/integration/admin/test_datasets_client.py b/tests/integration/admin/test_datasets_client.py index ad339dd..ee3739f 100644 --- a/tests/integration/admin/test_datasets_client.py +++ b/tests/integration/admin/test_datasets_client.py @@ -72,6 +72,26 @@ def test_deploy_dataset_with_end_block(self): assert response.job_id == 456 + @respx.mock + def test_deploy_dataset_with_new_fields(self): + """Test dataset deployment with retry_strategy, verify, worker_id.""" + deploy_response = {'job_id': 789} + respx.post('http://localhost:8080/datasets/_/test_dataset/versions/1.0.0/deploy').mock( + return_value=Response(200, json=deploy_response) + ) + + client = AdminClient('http://localhost:8080') + response = client.datasets.deploy( + '_', + 'test_dataset', + '1.0.0', + retry_strategy={'type': 'bounded', 'max_attempts': 3}, + verify=True, + worker_id='worker-eth-*', + ) + + assert response.job_id == 789 + @respx.mock def test_list_all_datasets(self): """Test listing all datasets.""" @@ -124,12 +144,16 @@ def test_get_versions(self): @respx.mock def test_get_version_info(self): - """Test getting specific version info.""" + """Test getting specific version info (now returns DatasetInfo).""" version_info = { - 'version': '1.0.0', - 'created_at': '2024-01-01T00:00:00Z', - 'updated_at': '2024-01-01T00:00:00Z', + 'namespace': '_', + 'name': 'eth_firehose', + 'revision': '1.0.0', 'manifest_hash': 'abc123', + 'kind': 'firehose', + 'start_block': 0, + 'finalized_blocks_only': False, + 'tables': ['blocks', 'transactions'], } respx.get('http://localhost:8080/datasets/_/eth_firehose/versions/1.0.0').mock( return_value=Response(200, json=version_info) @@ -139,7 +163,8 @@ def test_get_version_info(self): response = client.datasets.get_version('_', 'eth_firehose', '1.0.0') assert response.manifest_hash == 'abc123' - assert response.version == '1.0.0' + assert response.kind == 'firehose' + assert response.tables == ['blocks', 'transactions'] @respx.mock def test_get_manifest(self): @@ -182,3 +207,60 @@ def test_dataset_not_found(self): with pytest.raises(DatasetNotFoundError): client.datasets.get_version('_', 'missing', '1.0.0') + + @respx.mock + def test_list_jobs(self): + """Test listing jobs for a dataset version.""" + jobs_response = { + 'jobs': [ + { + 'id': 1, + 'status': 'Running', + 'descriptor': {}, + 'node_id': 'worker-1', + 'created_at': '2024-01-01T00:00:00Z', + 'updated_at': '2024-01-01T00:00:00Z', + } + ], + 'next_cursor': None, + } + respx.get('http://localhost:8080/datasets/_/eth_firehose/versions/latest/jobs').mock( + return_value=Response(200, json=jobs_response) + ) + + client = AdminClient('http://localhost:8080') + response = client.datasets.list_jobs('_', 'eth_firehose', 'latest') + + assert len(response.jobs) == 1 + assert response.jobs[0].status == 'Running' + + @respx.mock + def test_restore(self): + """Test restoring dataset physical tables.""" + restore_response = {'total_files': 42} + respx.post('http://localhost:8080/datasets/_/eth_firehose/versions/latest/restore').mock( + return_value=Response(202, json=restore_response) + ) + + client = AdminClient('http://localhost:8080') + result = client.datasets.restore('_', 'eth_firehose', 'latest') + + assert result.total_files == 42 + + @respx.mock + def test_restore_table(self): + """Test restoring a specific table.""" + respx.post('http://localhost:8080/datasets/_/eth_firehose/versions/latest/tables/blocks/restore').mock( + return_value=Response(200) + ) + + client = AdminClient('http://localhost:8080') + client.datasets.restore_table('_', 'eth_firehose', 'latest', 'blocks') + + @respx.mock + def test_delete_version(self): + """Test deleting a specific version.""" + respx.delete('http://localhost:8080/datasets/_/eth_firehose/versions/1.0.0').mock(return_value=Response(204)) + + client = AdminClient('http://localhost:8080') + client.datasets.delete_version('_', 'eth_firehose', '1.0.0') diff --git a/tests/integration/admin/test_jobs_client.py b/tests/integration/admin/test_jobs_client.py index 330940f..a48acf7 100644 --- a/tests/integration/admin/test_jobs_client.py +++ b/tests/integration/admin/test_jobs_client.py @@ -15,7 +15,14 @@ class TestJobsClient: @respx.mock def test_get_job(self): """Test getting job by ID.""" - job_response = {'id': 123, 'status': 'Running', 'descriptor': {}, 'node_id': 'worker-1'} + job_response = { + 'id': 123, + 'status': 'Running', + 'descriptor': {}, + 'node_id': 'worker-1', + 'created_at': '2024-01-01T00:00:00Z', + 'updated_at': '2024-01-01T00:00:00Z', + } respx.get('http://localhost:8080/jobs/123').mock(return_value=Response(200, json=job_response)) client = AdminClient('http://localhost:8080') @@ -41,8 +48,22 @@ def test_list_jobs(self): """Test listing jobs with pagination.""" jobs_response = { 'jobs': [ - {'id': 123, 'status': 'Running', 'descriptor': {}, 'node_id': 'worker-1'}, - {'id': 124, 'status': 'Completed', 'descriptor': {}, 'node_id': 'worker-2'}, + { + 'id': 123, + 'status': 'Running', + 'descriptor': {}, + 'node_id': 'worker-1', + 'created_at': '2024-01-01T00:00:00Z', + 'updated_at': '2024-01-01T00:00:00Z', + }, + { + 'id': 124, + 'status': 'Completed', + 'descriptor': {}, + 'node_id': 'worker-2', + 'created_at': '2024-01-01T00:00:00Z', + 'updated_at': '2024-01-01T00:00:00Z', + }, ], 'next_cursor': 125, } @@ -71,10 +92,22 @@ def test_list_jobs_with_cursor(self): @respx.mock def test_wait_for_completion_success(self): """Test waiting for job completion.""" - # First call: job is Running - # Second call: job is Completed - job_running = {'id': 123, 'status': 'Running', 'descriptor': {}, 'node_id': 'worker-1'} - job_completed = {'id': 123, 'status': 'Completed', 'descriptor': {}, 'node_id': 'worker-1'} + job_running = { + 'id': 123, + 'status': 'Running', + 'descriptor': {}, + 'node_id': 'worker-1', + 'created_at': '2024-01-01T00:00:00Z', + 'updated_at': '2024-01-01T00:00:00Z', + } + job_completed = { + 'id': 123, + 'status': 'Completed', + 'descriptor': {}, + 'node_id': 'worker-1', + 'created_at': '2024-01-01T00:00:00Z', + 'updated_at': '2024-01-01T00:00:00Z', + } route = respx.get('http://localhost:8080/jobs/123') route.side_effect = [Response(200, json=job_running), Response(200, json=job_completed)] @@ -87,7 +120,14 @@ def test_wait_for_completion_success(self): @respx.mock def test_wait_for_completion_timeout(self): """Test waiting for job with timeout.""" - job_running = {'id': 123, 'status': 'Running', 'descriptor': {}, 'node_id': 'worker-1'} + job_running = { + 'id': 123, + 'status': 'Running', + 'descriptor': {}, + 'node_id': 'worker-1', + 'created_at': '2024-01-01T00:00:00Z', + 'updated_at': '2024-01-01T00:00:00Z', + } respx.get('http://localhost:8080/jobs/123').mock(return_value=Response(200, json=job_running)) client = AdminClient('http://localhost:8080') @@ -99,14 +139,12 @@ def test_wait_for_completion_timeout(self): @respx.mock def test_stop_job(self): - """Test stopping a job.""" - respx.post('http://localhost:8080/jobs/123/stop').mock(return_value=Response(200)) + """Test stopping a job uses PUT.""" + respx.put('http://localhost:8080/jobs/123/stop').mock(return_value=Response(200)) client = AdminClient('http://localhost:8080') client.jobs.stop(123) - # Should complete without error - @respx.mock def test_delete_job(self): """Test deleting a job.""" @@ -115,14 +153,87 @@ def test_delete_job(self): client = AdminClient('http://localhost:8080') client.jobs.delete(123) - # Should complete without error - @respx.mock - def test_delete_many_jobs(self): - """Test deleting multiple jobs.""" + def test_delete_by_status(self): + """Test deleting jobs by status filter.""" respx.delete('http://localhost:8080/jobs').mock(return_value=Response(204)) client = AdminClient('http://localhost:8080') - client.jobs.delete_many([123, 124, 125]) + client.jobs.delete_by_status('Completed') + + @respx.mock + def test_create_job(self): + """Test creating a job.""" + from amp.admin.models import CreateJobRequest2, Kind1 + + create_response = {'job_id': 456} + respx.post('http://localhost:8080/jobs').mock(return_value=Response(201, json=create_response)) + + client = AdminClient('http://localhost:8080') + request = CreateJobRequest2(kind=Kind1.materialize_raw) + response = client.jobs.create(request) + + assert response.job_id == 456 + + @respx.mock + def test_get_events(self): + """Test getting job events.""" + events_response = { + 'job_id': 123, + 'events': [ + {'id': 1, 'event_type': 'SCHEDULED', 'created_at': '2024-01-01T00:00:00Z', 'node_id': 'worker-1'}, + {'id': 2, 'event_type': 'RUNNING', 'created_at': '2024-01-01T00:01:00Z', 'node_id': 'worker-1'}, + ], + } + respx.get('http://localhost:8080/jobs/123/events').mock(return_value=Response(200, json=events_response)) + + client = AdminClient('http://localhost:8080') + response = client.jobs.get_events(123) + + assert response.job_id == 123 + assert len(response.events) == 2 + assert response.events[0].event_type == 'SCHEDULED' + + @respx.mock + def test_get_event(self): + """Test getting a specific job event.""" + event_response = { + 'id': 1, + 'job_id': 123, + 'event_type': 'SCHEDULED', + 'created_at': '2024-01-01T00:00:00Z', + 'node_id': 'worker-1', + 'detail': {'message': 'Job scheduled'}, + } + respx.get('http://localhost:8080/jobs/123/events/1').mock(return_value=Response(200, json=event_response)) + + client = AdminClient('http://localhost:8080') + event = client.jobs.get_event(123, 1) + + assert event.id == 1 + assert event.event_type == 'SCHEDULED' + assert event.detail == {'message': 'Job scheduled'} + + @respx.mock + def test_get_progress(self): + """Test getting job progress.""" + progress_response = { + 'job_id': 123, + 'job_status': 'Running', + 'tables': { + 'blocks': { + 'current_block': 1000000, + 'start_block': 0, + 'files_count': 10, + 'total_size_bytes': 1024000, + } + }, + } + respx.get('http://localhost:8080/jobs/123/progress').mock(return_value=Response(200, json=progress_response)) + + client = AdminClient('http://localhost:8080') + progress = client.jobs.get_progress(123) - # Should complete without error + assert progress.job_id == 123 + assert progress.job_status == 'Running' + assert progress.tables['blocks'].current_block == 1000000 diff --git a/tests/integration/admin/test_revisions_client.py b/tests/integration/admin/test_revisions_client.py new file mode 100644 index 0000000..70acf6d --- /dev/null +++ b/tests/integration/admin/test_revisions_client.py @@ -0,0 +1,153 @@ +"""Integration tests for RevisionsClient with HTTP mocking.""" + +import pytest +import respx +from httpx import Response + +from amp.admin import AdminClient +from amp.admin.errors import RevisionNotFoundError + + +@pytest.mark.integration +class TestRevisionsClient: + """Test RevisionsClient operations with mocked HTTP responses.""" + + @respx.mock + def test_list_revisions(self): + """Test listing revisions.""" + revisions_response = [ + { + 'id': 1, + 'path': 's3://bucket/path1', + 'active': True, + 'writer': 100, + 'metadata': {'dataset_namespace': '_', 'dataset_name': 'eth', 'table_name': 'blocks'}, + }, + { + 'id': 2, + 'path': 's3://bucket/path2', + 'active': False, + 'writer': None, + 'metadata': {'dataset_namespace': '_', 'dataset_name': 'eth', 'table_name': 'txns'}, + }, + ] + respx.get('http://localhost:8080/revisions').mock(return_value=Response(200, json=revisions_response)) + + client = AdminClient('http://localhost:8080') + revisions = client.revisions.list() + + assert len(revisions) == 2 + assert revisions[0].id == 1 + assert revisions[0].active is True + assert revisions[1].active is False + + @respx.mock + def test_list_revisions_with_filters(self): + """Test listing revisions with active filter and pagination.""" + respx.get('http://localhost:8080/revisions').mock(return_value=Response(200, json=[])) + + client = AdminClient('http://localhost:8080') + revisions = client.revisions.list(active=True, limit=10, last_id=5) + + assert revisions == [] + + @respx.mock + def test_get_revision(self): + """Test getting a specific revision.""" + revision_response = { + 'id': 42, + 'path': 's3://bucket/path', + 'active': True, + 'writer': 100, + 'metadata': {'dataset_namespace': '_', 'dataset_name': 'eth', 'table_name': 'blocks'}, + } + respx.get('http://localhost:8080/revisions/42').mock(return_value=Response(200, json=revision_response)) + + client = AdminClient('http://localhost:8080') + rev = client.revisions.get(42) + + assert rev.id == 42 + assert rev.path == 's3://bucket/path' + assert rev.active is True + + @respx.mock + def test_get_revision_not_found(self): + """Test getting a non-existent revision.""" + error_response = {'error_code': 'REVISION_NOT_FOUND', 'error_message': 'Revision 999 not found'} + respx.get('http://localhost:8080/revisions/999').mock(return_value=Response(404, json=error_response)) + + client = AdminClient('http://localhost:8080') + + with pytest.raises(RevisionNotFoundError): + client.revisions.get(999) + + @respx.mock + def test_create_revision(self): + """Test creating a revision.""" + create_response = {'location_id': 42} + respx.post('http://localhost:8080/revisions').mock(return_value=Response(201, json=create_response)) + + client = AdminClient('http://localhost:8080') + result = client.revisions.create('_/eth_firehose@0.0.0', 'blocks', 's3://bucket/path') + + assert result.location_id == 42 + + @respx.mock + def test_delete_revision(self): + """Test deleting a revision.""" + respx.delete('http://localhost:8080/revisions/42').mock(return_value=Response(204)) + + client = AdminClient('http://localhost:8080') + client.revisions.delete(42) + + @respx.mock + def test_prune_revision(self): + """Test pruning a revision.""" + prune_response = {'files_scheduled': 10, 'gc_delay_secs': 3600} + respx.delete('http://localhost:8080/revisions/42/prune').mock(return_value=Response(200, json=prune_response)) + + client = AdminClient('http://localhost:8080') + result = client.revisions.prune(42) + + assert result.files_scheduled == 10 + assert result.gc_delay_secs == 3600 + + @respx.mock + def test_truncate_revision(self): + """Test truncating a revision.""" + truncate_response = {'files_deleted': 50} + respx.delete('http://localhost:8080/revisions/42/truncate').mock( + return_value=Response(200, json=truncate_response) + ) + + client = AdminClient('http://localhost:8080') + result = client.revisions.truncate(42) + + assert result.files_deleted == 50 + + @respx.mock + def test_activate_revision(self): + """Test activating a revision.""" + respx.post('http://localhost:8080/revisions/42/activate').mock(return_value=Response(200)) + + client = AdminClient('http://localhost:8080') + client.revisions.activate(42, '_/eth_firehose@0.0.0', 'blocks') + + @respx.mock + def test_deactivate_revision(self): + """Test deactivating a revision.""" + respx.post('http://localhost:8080/revisions/deactivate').mock(return_value=Response(200)) + + client = AdminClient('http://localhost:8080') + client.revisions.deactivate('_/eth_firehose@0.0.0', 'blocks') + + @respx.mock + def test_restore_revision(self): + """Test restoring a revision.""" + restore_response = {'total_files': 25} + respx.post('http://localhost:8080/revisions/42/restore').mock(return_value=Response(200, json=restore_response)) + + client = AdminClient('http://localhost:8080') + result = client.revisions.restore(42) + + assert result.total_files == 25 diff --git a/tests/unit/admin/test_models.py b/tests/unit/admin/test_models.py index f14580c..d88b176 100644 --- a/tests/unit/admin/test_models.py +++ b/tests/unit/admin/test_models.py @@ -49,9 +49,9 @@ def test_deploy_response(self): assert response.job_id == 123 - def test_deploy_response_job_id(self): - """Test DeployResponse has job_id field.""" - response = models.DeployResponse(job_id=456) + def test_create_job_response(self): + """Test CreateJobResponse model.""" + response = models.CreateJobResponse(job_id=456) assert response.job_id == 456 @@ -59,19 +59,31 @@ def test_deploy_response_job_id(self): class TestSchemaModels: """Test schema-related models.""" - def test_output_schema_request(self): - """Test OutputSchemaRequest model.""" - request = models.OutputSchemaRequest(sql_query='SELECT * FROM eth.blocks', is_sql_dataset=True) + def test_schema_request(self): + """Test SchemaRequest model.""" + request = models.SchemaRequest( + dependencies={'eth': '_/eth_firehose@0.0.0'}, + tables={'blocks': 'SELECT block_num FROM eth.blocks'}, + ) - assert request.sql_query == 'SELECT * FROM eth.blocks' - assert request.is_sql_dataset is True + assert request.dependencies == {'eth': '_/eth_firehose@0.0.0'} + assert request.tables == {'blocks': 'SELECT block_num FROM eth.blocks'} - def test_output_schema_request_defaults(self): - """Test OutputSchemaRequest with default values.""" - request = models.OutputSchemaRequest(sql_query='SELECT 1') + def test_schema_request_minimal(self): + """Test SchemaRequest with minimal fields.""" + request = models.SchemaRequest(tables={'t': 'SELECT 1'}) - assert request.sql_query == 'SELECT 1' - # is_sql_dataset should have a default if defined in the model + assert request.tables == {'t': 'SELECT 1'} + assert request.dependencies is None + assert request.functions is None + + def test_schema_response(self): + """Test SchemaResponse model.""" + response = models.SchemaResponse( + schemas={'blocks': {'arrow': {'fields': [{'name': 'block_num', 'type': 'int64'}]}}} + ) + + assert 'blocks' in response.schemas class TestEndBlockModel: @@ -79,18 +91,80 @@ class TestEndBlockModel: def test_end_block_with_value(self): """Test EndBlock with a value.""" - end_block = models.EndBlock(value='latest') + end_block = models.EndBlock(root='latest') - assert end_block.value == 'latest' + assert end_block.root == 'latest' def test_end_block_none(self): """Test EndBlock with None (continuous).""" - end_block = models.EndBlock(value=None) - - assert end_block.value is None + end_block = models.EndBlock(root=None) + + assert end_block.root is None + + +class TestRevisionModels: + """Test revision-related models.""" + + def test_revision_info(self): + """Test RevisionInfo model.""" + rev = models.RevisionInfo( + id=42, + path='s3://bucket/path', + active=True, + writer=100, + metadata=models.RevisionMetadataInfo( + dataset_namespace='_', + dataset_name='eth', + table_name='blocks', + ), + ) + + assert rev.id == 42 + assert rev.active is True + assert rev.metadata.table_name == 'blocks' + + def test_prune_response(self): + """Test PruneResponse model.""" + response = models.PruneResponse(files_scheduled=10, gc_delay_secs=3600) + + assert response.files_scheduled == 10 + + def test_truncate_response(self): + """Test TruncateResponse model.""" + response = models.TruncateResponse(files_deleted=50) + + assert response.files_deleted == 50 + + +class TestJobProgressModels: + """Test job progress models.""" + + def test_job_progress_response(self): + """Test JobProgressResponse model.""" + response = models.JobProgressResponse( + job_id=123, + job_status='Running', + tables={ + 'blocks': models.TableProgress( + current_block=1000000, + start_block=0, + files_count=10, + total_size_bytes=1024000, + ) + }, + ) - def test_end_block_default(self): - """Test EndBlock with default (no value provided).""" - end_block = models.EndBlock() - - assert end_block.value is None + assert response.job_id == 123 + assert response.tables['blocks'].current_block == 1000000 + + def test_table_progress(self): + """Test TableProgress model.""" + progress = models.TableProgress( + current_block=None, + start_block=None, + files_count=0, + total_size_bytes=0, + ) + + assert progress.current_block is None + assert progress.files_count == 0 diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index f9fd98b..93322d2 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -11,7 +11,7 @@ import pytest -from src.amp.admin.models import OutputSchemaResponse +from src.amp.admin.models import SchemaResponse from src.amp.client import Client, QueryBuilder @@ -242,18 +242,13 @@ class TestQueryBuilderManifest: def test_to_manifest_basic_structure(self): """Test that to_manifest generates correct manifest structure""" - # Create a mock client with admin API mock_client = Mock() - mock_schema_response = OutputSchemaResponse( - networks=['mainnet'], schema={'fields': [{'name': 'block_num', 'type': 'int64'}]} - ) - mock_client.schema.get_output_schema.return_value = mock_schema_response + mock_schema_response = SchemaResponse(schemas={'blocks': {'fields': [{'name': 'block_num', 'type': 'int64'}]}}) + mock_client.schema.analyze.return_value = mock_schema_response - # Create QueryBuilder and generate manifest qb = QueryBuilder(client=mock_client, query='SELECT block_num FROM eth.blocks') manifest = qb.to_manifest('blocks', network='mainnet') - # Verify structure assert manifest['kind'] == 'manifest' assert 'blocks' in manifest['tables'] assert manifest['tables']['blocks']['input']['sql'] == 'SELECT block_num FROM eth.blocks' @@ -263,106 +258,98 @@ def test_to_manifest_basic_structure(self): def test_to_manifest_with_dependencies(self): """Test that to_manifest includes dependencies""" - # Create a mock client with admin API mock_client = Mock() - mock_schema_response = OutputSchemaResponse( - networks=['mainnet'], schema={'fields': [{'name': 'block_num', 'type': 'int64'}]} - ) - mock_client.schema.get_output_schema.return_value = mock_schema_response + mock_schema_response = SchemaResponse(schemas={'blocks': {'fields': [{'name': 'block_num', 'type': 'int64'}]}}) + mock_client.schema.analyze.return_value = mock_schema_response - # Create QueryBuilder with dependencies qb = QueryBuilder(client=mock_client, query='SELECT block_num FROM eth.blocks') qb.with_dependency('eth', '_/eth_firehose@0.0.0') manifest = qb.to_manifest('blocks', network='mainnet') - # Verify dependencies are included assert manifest['dependencies'] == {'eth': '_/eth_firehose@0.0.0'} def test_to_manifest_with_multiple_dependencies(self): """Test that to_manifest includes multiple dependencies""" - # Create a mock client with admin API mock_client = Mock() - mock_schema_response = OutputSchemaResponse( - networks=['mainnet'], schema={'fields': [{'name': 'block_num', 'type': 'int64'}]} - ) - mock_client.schema.get_output_schema.return_value = mock_schema_response + mock_schema_response = SchemaResponse(schemas={'blocks': {'fields': [{'name': 'block_num', 'type': 'int64'}]}}) + mock_client.schema.analyze.return_value = mock_schema_response - # Create QueryBuilder with multiple dependencies qb = QueryBuilder(client=mock_client, query='SELECT e.block_num FROM eth.blocks e JOIN btc.blocks b') qb.with_dependency('eth', '_/eth_firehose@0.0.0').with_dependency('btc', '_/btc_firehose@1.2.3') manifest = qb.to_manifest('blocks', network='mainnet') - # Verify all dependencies are included assert manifest['dependencies'] == {'eth': '_/eth_firehose@0.0.0', 'btc': '_/btc_firehose@1.2.3'} def test_to_manifest_custom_network(self): """Test that to_manifest respects custom network parameter""" - # Create a mock client with admin API mock_client = Mock() - mock_schema_response = OutputSchemaResponse( - networks=['polygon'], schema={'fields': [{'name': 'block_num', 'type': 'int64'}]} - ) - mock_client.schema.get_output_schema.return_value = mock_schema_response + mock_schema_response = SchemaResponse(schemas={'blocks': {'fields': [{'name': 'block_num', 'type': 'int64'}]}}) + mock_client.schema.analyze.return_value = mock_schema_response - # Create QueryBuilder qb = QueryBuilder(client=mock_client, query='SELECT block_num FROM polygon.blocks') manifest = qb.to_manifest('blocks', network='polygon') - # Verify custom network assert manifest['tables']['blocks']['network'] == 'polygon' def test_to_manifest_calls_schema_api(self): """Test that to_manifest calls the schema API with correct parameters""" - # Create a mock client with admin API mock_client = Mock() - mock_schema_response = OutputSchemaResponse( - networks=['mainnet'], schema={'fields': [{'name': 'block_num', 'type': 'int64'}]} - ) - mock_client.schema.get_output_schema.return_value = mock_schema_response + mock_schema_response = SchemaResponse(schemas={'blocks': {'fields': [{'name': 'block_num', 'type': 'int64'}]}}) + mock_client.schema.analyze.return_value = mock_schema_response - # Create QueryBuilder query = 'SELECT block_num FROM eth.blocks WHERE block_num > 1000000' qb = QueryBuilder(client=mock_client, query=query) qb.to_manifest('blocks') - # Verify schema API was called correctly - mock_client.schema.get_output_schema.assert_called_once_with(query, is_sql_dataset=True) + mock_client.schema.analyze.assert_called_once_with( + dependencies=None, + tables={'blocks': query}, + ) + + def test_to_manifest_calls_schema_api_with_dependencies(self): + """Test that to_manifest passes dependencies to schema API""" + mock_client = Mock() + mock_schema_response = SchemaResponse(schemas={'blocks': {'fields': [{'name': 'block_num', 'type': 'int64'}]}}) + mock_client.schema.analyze.return_value = mock_schema_response + + query = 'SELECT block_num FROM eth.blocks' + qb = QueryBuilder(client=mock_client, query=query) + qb.with_dependency('eth', '_/eth_firehose@0.0.0') + qb.to_manifest('blocks') + + mock_client.schema.analyze.assert_called_once_with( + dependencies={'eth': '_/eth_firehose@0.0.0'}, + tables={'blocks': query}, + ) def test_to_manifest_matches_expected_format(self): """ Test that to_manifest generates a manifest matching reference manifest at tests/config/manifests/register_test_dataset__1_0_0.json """ - # Load the expected manifest manifest_path = Path(__file__).parent.parent / 'config' / 'manifests' / 'register_test_dataset__1_0_0.json' with open(manifest_path) as f: expected_manifest = json.load(f) - # Extract the data we need from the expected manifest expected_query = expected_manifest['tables']['erc20_transfers']['input']['sql'] expected_schema = expected_manifest['tables']['erc20_transfers']['schema'] expected_network = expected_manifest['tables']['erc20_transfers']['network'] - # Create a mock client with admin API mock_client = Mock() - mock_schema_response = OutputSchemaResponse(networks=['mainnet'], schema=expected_schema) - mock_client.schema.get_output_schema.return_value = mock_schema_response + mock_schema_response = SchemaResponse(schemas={'erc20_transfers': expected_schema}) + mock_client.schema.analyze.return_value = mock_schema_response - # Create QueryBuilder with the same query and dependency qb = QueryBuilder(client=mock_client, query=expected_query) qb.with_dependency('eth_firehose', '_/eth_firehose@0.0.0') - # Generate manifest generated_manifest = qb.to_manifest('erc20_transfers', network=expected_network) - # Verify the generated manifest matches the expected structure assert generated_manifest['kind'] == expected_manifest['kind'] assert generated_manifest['dependencies'] == expected_manifest['dependencies'] assert generated_manifest['functions'] == expected_manifest['functions'] - # Verify table structure assert 'erc20_transfers' in generated_manifest['tables'] generated_table = generated_manifest['tables']['erc20_transfers'] expected_table = expected_manifest['tables']['erc20_transfers'] @@ -370,47 +357,35 @@ def test_to_manifest_matches_expected_format(self): assert generated_table['input']['sql'] == expected_table['input']['sql'] assert generated_table['schema'] == expected_table['schema'] assert generated_table['network'] == expected_table['network'] - - # Verify schema fields match exactly assert generated_table['schema']['arrow']['fields'] == expected_table['schema']['arrow']['fields'] def test_to_manifest_serializes_to_valid_json(self): """Test that to_manifest generates a manifest that serializes to valid JSON with double quotes""" - # Create a mock client with admin API mock_client = Mock() - mock_schema_response = OutputSchemaResponse( - networks=['mainnet'], - schema={'arrow': {'fields': [{'name': 'block_num', 'type': 'UInt64', 'nullable': False}]}}, + mock_schema_response = SchemaResponse( + schemas={'blocks': {'arrow': {'fields': [{'name': 'block_num', 'type': 'UInt64', 'nullable': False}]}}}, ) - mock_client.schema.get_output_schema.return_value = mock_schema_response + mock_client.schema.analyze.return_value = mock_schema_response - # Create QueryBuilder qb = QueryBuilder(client=mock_client, query='SELECT block_num FROM eth.blocks') qb.with_dependency('eth', '_/eth_firehose@0.0.0') - # Generate manifest manifest = qb.to_manifest('blocks', network='mainnet') - # Serialize to JSON json_str = json.dumps(manifest, indent=2) - # Verify it uses double quotes (JSON standard) assert '"kind"' in json_str assert '"manifest"' in json_str assert '"dependencies"' in json_str assert '"tables"' in json_str assert '"blocks"' in json_str - # Verify no single quotes in the JSON (except in SQL queries which is OK) - # Count quotes - all structural quotes should be double quotes assert json_str.count('"kind":') == 1 assert json_str.count("'kind':") == 0 - # Verify it can be deserialized back deserialized = json.loads(json_str) assert deserialized == manifest - # Verify the JSON is valid and matches expected structure assert deserialized['kind'] == 'manifest' assert deserialized['dependencies'] == {'eth': '_/eth_firehose@0.0.0'} assert 'blocks' in deserialized['tables'] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..7fb0e00 --- /dev/null +++ b/uv.lock @@ -0,0 +1,2937 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" +resolution-markers = [ + "python_full_version >= '3.14' and platform_python_implementation != 'PyPy'", + "python_full_version == '3.13.*' and platform_python_implementation != 'PyPy'", + "python_full_version >= '3.14' and platform_python_implementation == 'PyPy'", + "python_full_version == '3.13.*' and platform_python_implementation == 'PyPy'", + "python_full_version < '3.13'", +] + +[[package]] +name = "adbc-driver-manager" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/2a/00fe4974b7d134c8d0691a87f09460d949e607e1ef65a022c665e8bde64f/adbc_driver_manager-1.8.0.tar.gz", hash = "sha256:88ca0f4d8c02fc6859629acaf0504620da17a39549e64d4098a3497f7f1eb2d0", size = 203568, upload-time = "2025-09-12T12:31:24.233Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/c7/05b5559eff9a42c53c47d86e32aa0b15bd206ef4be04f3a678da7871a8dd/adbc_driver_manager-1.8.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:0e6bbe0b026a17c69c1e7410a8df2366bb80803be0f0d8a7eed2defbed313a65", size = 537879, upload-time = "2025-09-12T12:30:00.798Z" }, + { url = "https://files.pythonhosted.org/packages/25/f0/d7ed70a28933e2c6b95455306c005d9022fc558e26e759ed65fce0537b79/adbc_driver_manager-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5f0f89d13b8f86dc20522988caceab37085fe155ebbea4e9013a7962170011c", size = 512702, upload-time = "2025-09-12T12:30:02.543Z" }, + { url = "https://files.pythonhosted.org/packages/37/a6/fc66e7b72857589ba5cdd0dcfc388ea746ed805caf4031580b1c065481fa/adbc_driver_manager-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd11c6ecdc8119641d2a929e50c9f6ff822b322859bf08a085e7ba9d1adb399", size = 3086175, upload-time = "2025-09-12T12:30:04.491Z" }, + { url = "https://files.pythonhosted.org/packages/e7/90/4780e8cab75f11644d260a73307445254288405352a99cfb3b2889c50e80/adbc_driver_manager-1.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f7689b0cf30d77532189b30762e3f6a347275e57e511e885f0eba45ce40ce02c", size = 3113622, upload-time = "2025-09-12T12:30:06.665Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b4/ed76afa37c344395a33d1f894dcd82b5cee2281925c235405a9078d10a29/adbc_driver_manager-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3f0454ec6fc2b5d3c3629b504ee65dbded2516412647070e26cdc9c14341ac74", size = 703323, upload-time = "2025-09-12T12:30:07.984Z" }, + { url = "https://files.pythonhosted.org/packages/56/79/76d505f43c6195920a41f812192bbd5fb1a490ade1c81fe5ba9f07a86f23/adbc_driver_manager-1.8.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:04e0676f7bd16dd7d7c403f506b7a22a542fe89f4471526c82cfd546353b125f", size = 536549, upload-time = "2025-09-12T12:30:09.513Z" }, + { url = "https://files.pythonhosted.org/packages/9f/1b/61e9badd21f0936a43692275f84dbf4baa4f39d4100042a14edbf9654a4d/adbc_driver_manager-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dddf0ae5b8d636015b1f7fc6972167c1824bd950f3ed6a178d083e89dfd322a", size = 510497, upload-time = "2025-09-12T12:30:10.837Z" }, + { url = "https://files.pythonhosted.org/packages/9c/52/501e0d11b2ba9fca1eb2698cb56ff14c94e8a1cad421a9c90c2e23edfbd8/adbc_driver_manager-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d70431e659e8e51d222fa238410085f0c13921154e0a17e9a687f7896667138f", size = 3085322, upload-time = "2025-09-12T12:30:12.893Z" }, + { url = "https://files.pythonhosted.org/packages/38/5e/0a79d48fe44cc8387221fff44dfa956c5ce6131a72f08e393748cbb090e0/adbc_driver_manager-1.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8b4d34618a5e64e678210dfdf76704f11e09529fc221dbd576ead6c14555883d", size = 3107704, upload-time = "2025-09-12T12:30:14.861Z" }, + { url = "https://files.pythonhosted.org/packages/71/42/689194767d6ec09bb9b9216c27000ff193199c9bd7d7d5c6c5aad1bc2400/adbc_driver_manager-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:82da1442b6d786d2f87ac0f3dd0bbc7462ec90cb3316168a4db88044d470baa2", size = 702235, upload-time = "2025-09-12T12:30:24.469Z" }, + { url = "https://files.pythonhosted.org/packages/83/45/4e98be65dab4e61c9c0227c4908ab9a5db1db320eec8badfd5b253c5854b/adbc_driver_manager-1.8.0-cp313-cp313t-macosx_10_15_x86_64.whl", hash = "sha256:bc1677c06998361b5c3237d9f408b69fb23942f7157e2dd4ce515f658a60d3d4", size = 551974, upload-time = "2025-09-12T12:30:16.782Z" }, + { url = "https://files.pythonhosted.org/packages/8f/4a/c4d83125e1dc0532006b3fd3c816a2c2956dedb881a89e0cb47f4eda1bcc/adbc_driver_manager-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:86cb394bdd3ac298761e0ff8ceab8ad9c2f6ce5650d7f4ac7c8609bc74876929", size = 529497, upload-time = "2025-09-12T12:30:18.756Z" }, + { url = "https://files.pythonhosted.org/packages/c7/6c/d1752ed66109fe1866d9aabe0f6a930b8443d8e62d17f333a38b97b37b85/adbc_driver_manager-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1a834f2f269285d1308aa97ae6000002acdb79d70733735f16b3c9918ca88c1f", size = 3148300, upload-time = "2025-09-12T12:30:21.301Z" }, + { url = "https://files.pythonhosted.org/packages/3d/59/971e28a01382590ead8352d83a2d77b1f8beb2c4cc1b59036e1b68fd59e1/adbc_driver_manager-1.8.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fcf38cc4b993336f49b6d1e407d4741ed1ea898f58088314005f8da7daf47db", size = 3134384, upload-time = "2025-09-12T12:30:23.252Z" }, + { url = "https://files.pythonhosted.org/packages/54/4e/0f826b68d5e0d50f8b1207514d0d17bf60663b7d51efd21f3754b5885450/adbc_driver_manager-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f954783e306ff1e1602d8390e74e00357142c382bff22ab159e8f94a95c8cfcb", size = 3082317, upload-time = "2025-09-12T12:30:26.8Z" }, + { url = "https://files.pythonhosted.org/packages/da/bf/ce5efe35be83b652e4b6059cfff48b59d648560a9dc99caac8da0a3441cd/adbc_driver_manager-1.8.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d5ec92af49a76345db1ae0a3890789797078b5b9948d550a47e8cfaa27cc19", size = 3089760, upload-time = "2025-09-12T12:30:28.772Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b3/d3254595b61890da1dc6d44178abe10262136d20aeffae4a86d3e289371e/adbc_driver_manager-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4f68df12cfbffaf4bec832ed406fb6ce978fd7dba8a4e8e377c9658fcd83b6a3", size = 3147028, upload-time = "2025-09-12T12:30:30.53Z" }, + { url = "https://files.pythonhosted.org/packages/68/ba/82d1f9521bc755d8d0d66eaac47032e147c2fe850eb308ba613710b27493/adbc_driver_manager-1.8.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a4402633d548e3ecdcf89a7133fd72b88a807a3c438e13bdb61ccc79d6239a65", size = 3133693, upload-time = "2025-09-12T12:30:32.357Z" }, +] + +[[package]] +name = "adbc-driver-postgresql" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "adbc-driver-manager" }, + { name = "importlib-resources" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/3a/3873d398f2df59bd1b20c803a24ef51068586554ea85ec8db6905f6ee639/adbc_driver_postgresql-1.8.0.tar.gz", hash = "sha256:66689c5616e41229c53ef222f63b60841f05b11610e60fb9029e54ac500e6d0d", size = 20306, upload-time = "2025-09-12T12:31:25.277Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/e9/2c68074a173fdaa69028f170317144607e1c6bd26dd343e014b1935ffc12/adbc_driver_postgresql-1.8.0-py3-none-macosx_10_15_x86_64.whl", hash = "sha256:1f155941e8b7b75210f78a128758b5e12a45c370d462ea0da42e7763b1e3e84e", size = 2691625, upload-time = "2025-09-12T12:30:43.672Z" }, + { url = "https://files.pythonhosted.org/packages/04/50/880b39754cf3b590e37f940dcfe45e72de18c8363fbc510fb22a26274e9c/adbc_driver_postgresql-1.8.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:22e11fe708303753e3bcac7798f4dc0f4a110db2b7447fddaf811b2d7af026ca", size = 3003079, upload-time = "2025-09-12T12:30:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/c0/75/fe2923c934dea56a05e331469c60bcac4558e656ccd4f1b2ecc252297ca6/adbc_driver_postgresql-1.8.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bed9d730905fddd61712fcad3954ccb7342c83a7f81bc51265eb33b1b83c5b6c", size = 3196334, upload-time = "2025-09-12T12:30:47.925Z" }, + { url = "https://files.pythonhosted.org/packages/36/43/5bb16e9220b23a21692e60c9f036c0e79b4f78409109df6c72b4b4abc945/adbc_driver_postgresql-1.8.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ef2fb1f60ef0e4195ddae0b8d52a5dd7f31d2b7d29ca88db1a805736ff5fbd05", size = 2855368, upload-time = "2025-09-12T12:30:51.127Z" }, + { url = "https://files.pythonhosted.org/packages/7a/36/2383ecf8888a77108b4cee249ee105d303851f9a08356fcc66d43bfbbc7c/adbc_driver_postgresql-1.8.0-py3-none-win_amd64.whl", hash = "sha256:08b78dd96d72d3855eb967bd46a7ca5e4fbc0b75c2a9fea6281d95cc6e934a8f", size = 2975792, upload-time = "2025-09-12T12:30:53.118Z" }, +] + +[[package]] +name = "altair" +version = "5.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "narwhals" }, + { name = "packaging" }, + { name = "typing-extensions", marker = "python_full_version < '3.14'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/b1/f2969c7bdb8ad8bbdda031687defdce2c19afba2aa2c8e1d2a17f78376d8/altair-5.5.0.tar.gz", hash = "sha256:d960ebe6178c56de3855a68c47b516be38640b73fb3b5111c2a9ca90546dd73d", size = 705305, upload-time = "2024-11-23T23:39:58.542Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/f3/0b6ced594e51cc95d8c1fc1640d3623770d01e4969d29c0bd09945fafefa/altair-5.5.0-py3-none-any.whl", hash = "sha256:91a310b926508d560fe0148d02a194f38b824122641ef528113d029fcd129f8c", size = 731200, upload-time = "2024-11-23T23:39:56.4Z" }, +] + +[[package]] +name = "amp" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "adbc-driver-manager" }, + { name = "adbc-driver-postgresql" }, + { name = "arro3-compute" }, + { name = "arro3-core" }, + { name = "base58" }, + { name = "eth-hash", extra = ["pysha3"] }, + { name = "eth-utils" }, + { name = "google-cloud-bigquery" }, + { name = "google-cloud-storage" }, + { name = "httpx" }, + { name = "pandas" }, + { name = "protobuf" }, + { name = "pyarrow" }, + { name = "pydantic" }, + { name = "typer" }, +] + +[package.dev-dependencies] +all-loaders = [ + { name = "clickhouse-connect" }, + { name = "deltalake" }, + { name = "lmdb" }, + { name = "prometheus-client" }, + { name = "psycopg2-binary" }, + { name = "pydantic" }, + { name = "pyiceberg", extra = ["sql-sqlite"] }, + { name = "redis" }, + { name = "snowflake-connector-python" }, + { name = "snowpipe-streaming" }, +] +clickhouse = [ + { name = "clickhouse-connect" }, +] +delta-lake = [ + { name = "deltalake" }, +] +dev = [ + { name = "altair" }, + { name = "datamodel-code-generator" }, + { name = "marimo" }, + { name = "ruff" }, +] +iceberg = [ + { name = "pydantic" }, + { name = "pyiceberg", extra = ["sql-sqlite"] }, +] +lmdb = [ + { name = "lmdb" }, +] +metrics = [ + { name = "prometheus-client" }, +] +postgresql = [ + { name = "psycopg2-binary" }, +] +redis = [ + { name = "redis" }, +] +snowflake = [ + { name = "snowflake-connector-python" }, + { name = "snowpipe-streaming" }, +] +test = [ + { name = "docker" }, + { name = "psutil" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-benchmark" }, + { name = "pytest-cov" }, + { name = "pytest-mock" }, + { name = "pytest-xdist" }, + { name = "respx" }, + { name = "testcontainers" }, +] + +[package.metadata] +requires-dist = [ + { name = "adbc-driver-manager", specifier = ">=1.5.0" }, + { name = "adbc-driver-postgresql", specifier = ">=1.5.0" }, + { name = "arro3-compute", specifier = ">=0.5.1" }, + { name = "arro3-core", specifier = ">=0.5.1" }, + { name = "base58", specifier = ">=2.1.1" }, + { name = "eth-hash", extras = ["pysha3"], specifier = ">=0.7.1" }, + { name = "eth-utils", specifier = ">=5.2.0" }, + { name = "google-cloud-bigquery", specifier = ">=3.30.0" }, + { name = "google-cloud-storage", specifier = ">=3.1.0" }, + { name = "httpx", specifier = ">=0.27.0" }, + { name = "pandas", specifier = ">=2.3.1" }, + { name = "protobuf", specifier = ">=4.21.0" }, + { name = "pyarrow", specifier = ">=20.0.0" }, + { name = "pydantic", specifier = ">=2.0,<2.12" }, + { name = "typer", specifier = ">=0.15.2" }, +] + +[package.metadata.requires-dev] +all-loaders = [ + { name = "clickhouse-connect", specifier = ">=0.8.0" }, + { name = "deltalake", specifier = ">=1.0.2" }, + { name = "lmdb", specifier = ">=1.4.0" }, + { name = "prometheus-client", specifier = ">=0.20.0" }, + { name = "psycopg2-binary", specifier = ">=2.9.0" }, + { name = "pydantic", specifier = ">=2.0,<2.12" }, + { name = "pyiceberg", extras = ["sql-sqlite"], specifier = ">=0.10.0" }, + { name = "redis", specifier = ">=4.5.0" }, + { name = "snowflake-connector-python", specifier = ">=4.0.0" }, + { name = "snowpipe-streaming", specifier = ">=1.0.0" }, +] +clickhouse = [{ name = "clickhouse-connect", specifier = ">=0.8.0" }] +delta-lake = [{ name = "deltalake", specifier = ">=1.0.2" }] +dev = [ + { name = "altair", specifier = ">=5.5.0" }, + { name = "datamodel-code-generator", specifier = ">=0.25.0" }, + { name = "marimo", specifier = ">=0.11.31" }, + { name = "ruff", specifier = ">=0.8.0" }, +] +iceberg = [ + { name = "pydantic", specifier = ">=2.0,<2.12" }, + { name = "pyiceberg", extras = ["sql-sqlite"], specifier = ">=0.10.0" }, +] +lmdb = [{ name = "lmdb", specifier = ">=1.4.0" }] +metrics = [{ name = "prometheus-client", specifier = ">=0.20.0" }] +postgresql = [{ name = "psycopg2-binary", specifier = ">=2.9.0" }] +redis = [{ name = "redis", specifier = ">=4.5.0" }] +snowflake = [ + { name = "snowflake-connector-python", specifier = ">=4.0.0" }, + { name = "snowpipe-streaming", specifier = ">=1.0.0" }, +] +test = [ + { name = "docker", specifier = ">=6.0.0" }, + { name = "psutil", specifier = ">=5.9.0" }, + { name = "pytest", specifier = ">=8.3.5" }, + { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytest-benchmark", specifier = ">=4.0.0" }, + { name = "pytest-cov", specifier = ">=4.0.0" }, + { name = "pytest-mock", specifier = ">=3.10.0" }, + { name = "pytest-xdist", specifier = ">=3.0.0" }, + { name = "respx", specifier = ">=0.21.0" }, + { name = "testcontainers", specifier = ">=4.0.0" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, +] + +[[package]] +name = "argcomplete" +version = "3.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" }, +] + +[[package]] +name = "arro3-compute" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "arro3-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/90/8b/89d1bbd0c6e535f20951c8fcff8b05d899d985ea746d40921d85055f766e/arro3_compute-0.6.3.tar.gz", hash = "sha256:035cc45bd2e7fa1998ed4e0b9395faa11aca059f0c82fcd8e5a22193ab5a0cc4", size = 89274, upload-time = "2025-09-17T21:59:41.357Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/4b/2b72528c5b1b6411c14d7aa6eb2922158ff2815ef56cae165ecffdbdf609/arro3_compute-0.6.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d886c0304dbca3ab75ff2eae967c21c87d0806576fe23bb20e01df225a5af926", size = 2801209, upload-time = "2025-09-17T21:56:40.854Z" }, + { url = "https://files.pythonhosted.org/packages/5d/25/1fc5cdfa2875548db28e8e2385d212aac19840cde6f0300c749e6bc3706d/arro3_compute-0.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fd4642a927362b11d09f4dba24d86d9cde930bfb292e92a2706b71fbdd031bdf", size = 2443220, upload-time = "2025-09-17T21:56:44.384Z" }, + { url = "https://files.pythonhosted.org/packages/8c/77/b504bbc59d232515f61b923258c1c7ea26e0d8cd99ad4a692fd4b93ee445/arro3_compute-0.6.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:997e73ed33028f7cc71ce43d828d0cab69769fa5e40b567430bb74839393273e", size = 3087189, upload-time = "2025-09-17T21:56:48.531Z" }, + { url = "https://files.pythonhosted.org/packages/74/5c/4f4af43abcaa4c2f62f0fd19af9d08975c5c00548b0dd03fb2634c9ae045/arro3_compute-0.6.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:846af7bd55fe7369382b8a876eb1747e6d478f7241ce2d13989b22cf5e2088dd", size = 2972745, upload-time = "2025-09-17T21:56:51.469Z" }, + { url = "https://files.pythonhosted.org/packages/fd/bd/da58027cb3d7c14b4d491e1a7be7ac141c443086c97ac848b4b29012afce/arro3_compute-0.6.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e2ae18f0045712e218c20d76dace8986358d82485064f643dd9610de2235d69", size = 3418636, upload-time = "2025-09-17T21:56:54.726Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e4/e7864275f0725774d835e8391131e7d4494fed1b605e3eb2c34f3ae6dbcc/arro3_compute-0.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d671af3a2122cf589bcdbd5662533e033bcb652fe0340555de6dc1a9a235fab7", size = 2922541, upload-time = "2025-09-17T21:56:58.307Z" }, + { url = "https://files.pythonhosted.org/packages/b9/fc/751b496d25777ea54dd27b9c66ad0e19a34f5eb11e5dc718f5f31b1222b9/arro3_compute-0.6.3-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:4b214749a2ac942538937c372a040a9e25cce57a00d98ba6451a7d0d68253c8d", size = 2611347, upload-time = "2025-09-17T21:57:01.235Z" }, + { url = "https://files.pythonhosted.org/packages/26/77/d9cc1e25cd6caab0ce4afec46577e316aca4783253a00a13ac21bd5873b6/arro3_compute-0.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3af1cec915ab8cbd215e18d48b7de7a8e72c7cfab57d067f5bce0e541854148f", size = 3234414, upload-time = "2025-09-17T21:57:04.581Z" }, + { url = "https://files.pythonhosted.org/packages/b6/97/1998a75d916b29bc9a708fd56715db7fa5e4ad9199af9e178a4a40a0b6a0/arro3_compute-0.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fac879aa1910d156486e794366963c7b626f9c68b957fea2768de32de359f4ac", size = 2742230, upload-time = "2025-09-17T21:57:08.137Z" }, + { url = "https://files.pythonhosted.org/packages/15/76/d1ba7a4b51eb07c02a5e73fa4c86170ee7746c5ef5a695af241c2d6bd8cd/arro3_compute-0.6.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a044f7685ecab5b48afd8a84cb5f3b4edd5978c8f7faa5b12738bad77f5ca3fc", size = 3356256, upload-time = "2025-09-17T21:57:11.537Z" }, + { url = "https://files.pythonhosted.org/packages/50/40/d30d0498f1d63d4e820a7d90e14a106ac428bfa7541bd65cf1a9941a88a2/arro3_compute-0.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:afa8a13f343326b17a6756727d7d97bdfc588a7fa84458edc09ca70c17f408c3", size = 3294433, upload-time = "2025-09-17T21:57:15.056Z" }, + { url = "https://files.pythonhosted.org/packages/a5/de/2e0b8d415369a6c54e56d7566a940141ba1acd5a30e8591182a3eb6ab0b6/arro3_compute-0.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:86a6a2b051e17034d1ca04af74b9cbd1714f8851bcb3cb032689dfaae93b0a33", size = 3090963, upload-time = "2025-09-17T21:57:18.469Z" }, + { url = "https://files.pythonhosted.org/packages/90/7f/5c698a1b3766282d26d8a868ebe9264a1790f9915199ac207918711b5e5e/arro3_compute-0.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:c52a83181780c09b975a4f04ccc15ac37247b230ce0fd5ae4b741a269197b459", size = 2999911, upload-time = "2025-09-17T21:57:21.842Z" }, + { url = "https://files.pythonhosted.org/packages/0a/40/7ee8eee7b302e9c0f3e79e40e0a4eb1633b700519ecae188a1cc02ac100e/arro3_compute-0.6.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0a76cbdff54fd5353de05cfff1c520a1c1dca4c1c5df0592baf0231194e9c6bd", size = 2801172, upload-time = "2025-09-17T21:57:25.379Z" }, + { url = "https://files.pythonhosted.org/packages/9f/60/ddd301446c1f60301b77fb438d92162eff1dad3fc8441cd9650cde1d24ee/arro3_compute-0.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:787d3c93825b9dc207374a09067ce15673587ac4d2876e9061e3203d1f0c0057", size = 2443283, upload-time = "2025-09-17T21:57:28.593Z" }, + { url = "https://files.pythonhosted.org/packages/87/df/2a3abb2943eae38fff8c4a0e8cd4a25e46f97d0f2568f985978a0fd3cf77/arro3_compute-0.6.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb542dc02bba7781ff7c8b1f5eb1db1b980db7fccfb229f1d796d22a5255b031", size = 3087391, upload-time = "2025-09-17T21:57:32.891Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a0/cb678eacb9248b2f075a9dfeaf5ab0b65cceb74c463982df6cfa67c7a6a6/arro3_compute-0.6.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c762558bc0d63166d72a125506104b6beee053738900d6c4cb82f218109212e", size = 2973095, upload-time = "2025-09-17T21:57:36.142Z" }, + { url = "https://files.pythonhosted.org/packages/07/73/e0b7eddc02c0fbcd274e4c87131b210dbe389a548d0fb470a8a1d3a26d53/arro3_compute-0.6.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17cceb1b077c8fe914ed7f9126b33bd482a7ad9e42733d1ea04d6377c4e9553c", size = 3428880, upload-time = "2025-09-17T21:57:39.158Z" }, + { url = "https://files.pythonhosted.org/packages/5a/ce/3ad5331298f13ce24e1b78f955e9f6490fe5da30221315d49dd2c09031fb/arro3_compute-0.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:905fa6d41474ae1e60464442b5ab168aa620040bf6f40592545d14d7ecf396a3", size = 2922551, upload-time = "2025-09-17T21:57:42.401Z" }, + { url = "https://files.pythonhosted.org/packages/29/07/da607c638fd33ebac02b87f5b033a8c91f6c425cdbdbfd58bdcff7a61c62/arro3_compute-0.6.3-cp313-cp313-manylinux_2_24_aarch64.whl", hash = "sha256:29b8c5d920b2e4f46b97f2d086973085bda66ebf123c2bba21092b32e6dc8106", size = 2611429, upload-time = "2025-09-17T21:57:45.872Z" }, + { url = "https://files.pythonhosted.org/packages/84/e2/35c069114f58b3211a2679879684571525d333628f1e9b09257826f32ab0/arro3_compute-0.6.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00bdf3d3dd58d29a5bd2dc0a42eeae6a541a8cadb8fffb7bbc3b501c9d0ab96d", size = 3234427, upload-time = "2025-09-17T21:57:49.035Z" }, + { url = "https://files.pythonhosted.org/packages/b9/ea/89369c242854f0c66f138aa642995f0ec8d01fdac79d06d5be398d2c7b3a/arro3_compute-0.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:56bf213c910dc609d7a6e6c24d4003ed496627c6ec9e5bd65fccae23a959031f", size = 2742057, upload-time = "2025-09-17T21:57:52.451Z" }, + { url = "https://files.pythonhosted.org/packages/8b/88/ea54e6bc3a2eb5b08573cb254ef6e9ff71897d95a3052c3bf7b19c042885/arro3_compute-0.6.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f9dcf43eb2676424a1d3df14c5dc60dc68c50b039aa79a584d3b86856af303b1", size = 3356220, upload-time = "2025-09-17T21:57:55.727Z" }, + { url = "https://files.pythonhosted.org/packages/1a/9a/d33300a8bf74f603471d08b507ef6e6cb3a4457d215c2906c98b4d407f04/arro3_compute-0.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8699e08b1e307a41853a73e58173addaddca4140ba534325cd6551d4b60e57d3", size = 3294545, upload-time = "2025-09-17T21:57:59.154Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2e/8e02a380270ac495a3c7444abbe56f4f4d5b5a58f54a75154dac1af60156/arro3_compute-0.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:986f69f32f6a81703fa3ccb2a0648cdef8bec8bb6739d5f3d3c39d8d78c0312b", size = 3090985, upload-time = "2025-09-17T21:58:02.801Z" }, + { url = "https://files.pythonhosted.org/packages/29/11/5436b09eed311651dc70a9819c75a8bc4051bbcc3c5440e5adf95fcf0853/arro3_compute-0.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:a16245a490b2436a7c03be42e66f664bd46d32b70b37b845a7c8992c5d33b91c", size = 2999694, upload-time = "2025-09-17T21:58:05.907Z" }, +] + +[[package]] +name = "arro3-core" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/08/44/104ec426c1bed146deae8fdf1f9b8aa1fd54872fc05768059e47d642285b/arro3_core-0.6.3.tar.gz", hash = "sha256:5da776dda9ac278d8ae61f6dbc5bc4ce95ac9869d57940938eb10115ce4b8edf", size = 107926, upload-time = "2025-09-17T21:59:52.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/0a/56fae7e43377e7f3b4d12cf2610600e9dd7bca80178dbedc9d9c25d2c85e/arro3_core-0.6.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:831b16044e791d7bd93aa47ebbdce219ef7e8613a04802149cd61584b236cead", size = 2667943, upload-time = "2025-09-17T21:56:54.157Z" }, + { url = "https://files.pythonhosted.org/packages/3c/d8/589a4a1ef136bca84d7b0c20a82fbfb7526b81611a8407a94c8a82a82212/arro3_core-0.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1ed625996c63443b354fed1c0756dbfa55f3b2cd5adbc4203adbfdb79549d49f", size = 2359479, upload-time = "2025-09-17T21:56:57.364Z" }, + { url = "https://files.pythonhosted.org/packages/79/7f/67729c440e3d1a41e0fea10738328785c5b3e5e78776c985a46f925e2de6/arro3_core-0.6.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a125b1c69b556bf3ad6f5fc31910489c987612c30e160b8634d86f63f53f6099", size = 2869113, upload-time = "2025-09-17T21:57:00.592Z" }, + { url = "https://files.pythonhosted.org/packages/af/29/ec07886805640b5fe7d9d9a1f6ff8286bd43e3a17e76c9c6500f6a7cb2e1/arro3_core-0.6.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4eaee19aef578340eb1a21358ec74a076730a0034f9201fb8300f68161442da", size = 2884956, upload-time = "2025-09-17T21:57:03.679Z" }, + { url = "https://files.pythonhosted.org/packages/42/36/95006f8ffe9ac402b9fdc30c1219e4b4c84b015a2044a64881665a39d031/arro3_core-0.6.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d0e3cd65d3d8291a1264f63f4d52fdec6f568b59b251b06da262c04366c4e94", size = 3128632, upload-time = "2025-09-17T21:57:07.424Z" }, + { url = "https://files.pythonhosted.org/packages/8b/68/2e26a8ab469a0c5bcee59a1237c77045a9190ff226d5802ba771ea04213c/arro3_core-0.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace96f1a933b7acc64b66f9f9b2bccac79244c693cdfc74ed7eaef92c05c4db8", size = 2769161, upload-time = "2025-09-17T21:57:10.643Z" }, + { url = "https://files.pythonhosted.org/packages/db/23/36abe2e3c146442fdec5b982fad757002469276e7cf65e8b64dad927129a/arro3_core-0.6.3-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:92d75b1b5e6faaa44aa3e24543e8bfb06703e510d2c98104eae4ef36c234fbd8", size = 2514233, upload-time = "2025-09-17T21:57:14.236Z" }, + { url = "https://files.pythonhosted.org/packages/28/99/467096bea0b81f9bb959e2d399a8dc88886a4f2c20342c26e82ad8bc643b/arro3_core-0.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f222ff4aec28cb10a422bd36d15c947f5b134682bb60c546131c5fdb2f9d75e0", size = 3028860, upload-time = "2025-09-17T21:57:17.905Z" }, + { url = "https://files.pythonhosted.org/packages/40/61/430d9f8006429c9e1e8961aaeb4fd6cd56dc5cf9eb457fd368b9b7428058/arro3_core-0.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:81bbb41244ad6ed9cbf292ed0fa22ce39ac1280cd2062faa80d6d11841517caa", size = 2659640, upload-time = "2025-09-17T21:57:21.114Z" }, + { url = "https://files.pythonhosted.org/packages/02/79/93474994e5babfe9eedbe6f2d3f45b303d9bd0c3729a7a432f1d3db4f99f/arro3_core-0.6.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b7b0295a1b792b62de0110d73e3abc77c54482e0e5bb82e06a3809bdd0c7e5c7", size = 3132602, upload-time = "2025-09-17T21:57:24.596Z" }, + { url = "https://files.pythonhosted.org/packages/87/8d/c750a612aa6c23184d078de3546c3d775ed7fc050e5fbb5752798610f687/arro3_core-0.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ce2bc0bba2bab845d6974a9bebe7607e8edd273628d71fbe4513e8f28f44622", size = 3099007, upload-time = "2025-09-17T21:57:27.872Z" }, + { url = "https://files.pythonhosted.org/packages/86/d3/7e582fc2e413c26e6dcd993428663db33bbea26be6f3911dcb726768b4d4/arro3_core-0.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed285fba9dab1cebf3bf63a98df83e93d4fd70933d5af1dc24b6164032d845ee", size = 2936878, upload-time = "2025-09-17T21:57:31.193Z" }, + { url = "https://files.pythonhosted.org/packages/9a/13/5aed08d87a396c0b8441871f703ef06c2364d98ef1fbfa73b1c259457212/arro3_core-0.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:a564470bd529facffd71e31e11b8b38cc9ca207745b6349f5923fcd39bf75877", size = 2835145, upload-time = "2025-09-17T21:57:35.296Z" }, + { url = "https://files.pythonhosted.org/packages/a6/27/75f729785396e5780a08b7c63f3f09b0545a718e5a38976d815ccf0c51e2/arro3_core-0.6.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5510c501252212fe6b5427f465019de1d92c9ad8e8d1c0b268ab952b1888d9f7", size = 2667560, upload-time = "2025-09-17T21:57:38.531Z" }, + { url = "https://files.pythonhosted.org/packages/db/c4/d3730b7f4e7f01e502f79966733b4821388c23e7c343483f69dad0f99568/arro3_core-0.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3aa049228302c81b996fb6e5917dd6fe1cb0f0699b69e5031e9e22331379c5b0", size = 2359471, upload-time = "2025-09-17T21:57:41.714Z" }, + { url = "https://files.pythonhosted.org/packages/96/47/f7b0589c9ba7b4d0b09fc363e2b8fd62ab897c81494be2f099647d27df15/arro3_core-0.6.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae4ba5141376c668f8cc5b0607f1e1e23713d1fe922e77f153648aa21739f2de", size = 2867954, upload-time = "2025-09-17T21:57:44.884Z" }, + { url = "https://files.pythonhosted.org/packages/00/13/7a2ed0b27cc0ce265022f338446c0c133ad7f2ccd9746934203728786be4/arro3_core-0.6.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e45fa8a90ef779495b52932eaca374d69b5f0683a3458a66f002a107857f43b4", size = 2884493, upload-time = "2025-09-17T21:57:48.351Z" }, + { url = "https://files.pythonhosted.org/packages/d9/07/d1ada59bb461e0103323cb2096ffa9e0590d8504bd624745ec2d900eeab1/arro3_core-0.6.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b79291b12f3cb3f4538b07770cba15b4013ecebca8e28230ee6f08665e3b8d4e", size = 3128265, upload-time = "2025-09-17T21:57:51.651Z" }, + { url = "https://files.pythonhosted.org/packages/23/fe/3f19abcf6c0fc788df79366e5bfee643f1d0f20493a906e660bc4041f4a0/arro3_core-0.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a450d3904e834ae6a21866538e5ddf43f676a7f3881321835390d061953a98", size = 2768547, upload-time = "2025-09-17T21:57:55.056Z" }, + { url = "https://files.pythonhosted.org/packages/49/3e/b3c2a260c1e2ade25998540a151be37b000849c7d21af068f70d824f9681/arro3_core-0.6.3-cp313-cp313-manylinux_2_24_aarch64.whl", hash = "sha256:02e86a9b932639e6282ef8b5ad6a0d532d1e4909b8c3d36e8a82b8cefa3aa759", size = 2514159, upload-time = "2025-09-17T21:57:58.348Z" }, + { url = "https://files.pythonhosted.org/packages/37/56/fd6bd638be26dccb237d3c51b221b2a6e90ae70749a103a505c05387f05b/arro3_core-0.6.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b0115eb6a91da54dc00e99d609b37fff460aca1d3e04ffc9a827626938c5fde", size = 3028141, upload-time = "2025-09-17T21:58:01.84Z" }, + { url = "https://files.pythonhosted.org/packages/ef/29/ed5048111de3c8b65a0d4b95bd86859d88efbe9a21d2a3194f01cccd79bf/arro3_core-0.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2c29251db308c087a9bb49a71ea2e921333e8951edecfcc9659cf87a2de237e5", size = 2659264, upload-time = "2025-09-17T21:58:05.259Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2e/69c651cdbc56c250dee8f44ed5a4ec11824be9e9f3513bc0ae0b1824941a/arro3_core-0.6.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d45a6affb74f20a7c6e049f2abba73e687f6cd674e2cb747e3cfe8a012560fda", size = 3131835, upload-time = "2025-09-17T21:58:08.435Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b6/82947fe4c322ef60315a12023e27048078dcf90967ec2b373687e2f9dfd9/arro3_core-0.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:312d70f7c69436a3eac716995c4fdafe94acf750d0037fa2495936dff8feaa0b", size = 3098165, upload-time = "2025-09-17T21:58:11.875Z" }, + { url = "https://files.pythonhosted.org/packages/1b/05/1ed10598ea96d80d4b2db9f3ac0b19390fe996c8b6f342c40f0fac22115d/arro3_core-0.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d8f8dd075c2f69e36b968bca420cd0c6885f8f877d544a0b6af5872deeb4ab2", size = 2936341, upload-time = "2025-09-17T21:58:15.112Z" }, + { url = "https://files.pythonhosted.org/packages/32/0e/3eadf8cf4be14df1d6c991b094685da9fd605d5727d969640a2d85873e29/arro3_core-0.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:4f69866656e8a2e75495bf8c5ed8138f4ca7169b6532e66f6c7f7e37bd96b21f", size = 2834121, upload-time = "2025-09-17T21:58:18.431Z" }, +] + +[[package]] +name = "asn1crypto" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/cf/d547feed25b5244fcb9392e288ff9fdc3280b10260362fc45d37a798a6ee/asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", size = 121080, upload-time = "2022-03-15T14:46:52.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/7f/09065fd9e27da0eda08b4d6897f1c13535066174cc023af248fc2a8d5e5a/asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67", size = 105045, upload-time = "2022-03-15T14:46:51.055Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "base58" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/45/8ae61209bb9015f516102fa559a2914178da1d5868428bd86a1b4421141d/base58-2.1.1.tar.gz", hash = "sha256:c5d0cb3f5b6e81e8e35da5754388ddcc6d0d14b6c6a132cb93d69ed580a7278c", size = 6528, upload-time = "2021-10-30T22:12:17.858Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/45/ec96b29162a402fc4c1c5512d114d7b3787b9d1c2ec241d9568b4816ee23/base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2", size = 5621, upload-time = "2021-10-30T22:12:16.658Z" }, +] + +[[package]] +name = "black" +version = "25.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "pytokens" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4b/43/20b5c90612d7bdb2bdbcceeb53d588acca3bb8f0e4c5d5c751a2c8fdd55a/black-25.9.0.tar.gz", hash = "sha256:0474bca9a0dd1b51791fcc507a4e02078a1c63f6d4e4ae5544b9848c7adfb619", size = 648393, upload-time = "2025-09-19T00:27:37.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/8e/319cfe6c82f7e2d5bfb4d3353c6cc85b523d677ff59edc61fdb9ee275234/black-25.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1b9dc70c21ef8b43248f1d86aedd2aaf75ae110b958a7909ad8463c4aa0880b0", size = 1742012, upload-time = "2025-09-19T00:33:08.678Z" }, + { url = "https://files.pythonhosted.org/packages/94/cc/f562fe5d0a40cd2a4e6ae3f685e4c36e365b1f7e494af99c26ff7f28117f/black-25.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8e46eecf65a095fa62e53245ae2795c90bdecabd53b50c448d0a8bcd0d2e74c4", size = 1581421, upload-time = "2025-09-19T00:35:25.937Z" }, + { url = "https://files.pythonhosted.org/packages/84/67/6db6dff1ebc8965fd7661498aea0da5d7301074b85bba8606a28f47ede4d/black-25.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9101ee58ddc2442199a25cb648d46ba22cd580b00ca4b44234a324e3ec7a0f7e", size = 1655619, upload-time = "2025-09-19T00:30:49.241Z" }, + { url = "https://files.pythonhosted.org/packages/10/10/3faef9aa2a730306cf469d76f7f155a8cc1f66e74781298df0ba31f8b4c8/black-25.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:77e7060a00c5ec4b3367c55f39cf9b06e68965a4f2e61cecacd6d0d9b7ec945a", size = 1342481, upload-time = "2025-09-19T00:31:29.625Z" }, + { url = "https://files.pythonhosted.org/packages/48/99/3acfea65f5e79f45472c45f87ec13037b506522719cd9d4ac86484ff51ac/black-25.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0172a012f725b792c358d57fe7b6b6e8e67375dd157f64fa7a3097b3ed3e2175", size = 1742165, upload-time = "2025-09-19T00:34:10.402Z" }, + { url = "https://files.pythonhosted.org/packages/3a/18/799285282c8236a79f25d590f0222dbd6850e14b060dfaa3e720241fd772/black-25.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3bec74ee60f8dfef564b573a96b8930f7b6a538e846123d5ad77ba14a8d7a64f", size = 1581259, upload-time = "2025-09-19T00:32:49.685Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ce/883ec4b6303acdeca93ee06b7622f1fa383c6b3765294824165d49b1a86b/black-25.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b756fc75871cb1bcac5499552d771822fd9db5a2bb8db2a7247936ca48f39831", size = 1655583, upload-time = "2025-09-19T00:30:44.505Z" }, + { url = "https://files.pythonhosted.org/packages/21/17/5c253aa80a0639ccc427a5c7144534b661505ae2b5a10b77ebe13fa25334/black-25.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:846d58e3ce7879ec1ffe816bb9df6d006cd9590515ed5d17db14e17666b2b357", size = 1343428, upload-time = "2025-09-19T00:32:13.839Z" }, + { url = "https://files.pythonhosted.org/packages/1b/46/863c90dcd3f9d41b109b7f19032ae0db021f0b2a81482ba0a1e28c84de86/black-25.9.0-py3-none-any.whl", hash = "sha256:474b34c1342cdc157d307b56c4c65bce916480c4a8f6551fdc6bf9b486a7c4ae", size = 203363, upload-time = "2025-09-19T00:27:35.724Z" }, +] + +[[package]] +name = "boto3" +version = "1.40.48" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/32/187aa2a09b385f12a32b02179892b7fa566844f68c0e478099a2102c7c62/boto3-1.40.48.tar.gz", hash = "sha256:b993bbef91f3796f0ae69b2a310a6cef41a06348ed80961f0ebc804680d8e9a4", size = 111611, upload-time = "2025-10-08T19:24:24.417Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/48/e451965569ae420164bd2b59c04eef8320a29f6b4721bfefa82ee1d1dae1/boto3-1.40.48-py3-none-any.whl", hash = "sha256:8a5fb8b5509cd5ddaf3d1d1f0385c974038b47492ca25f3414042676d188f635", size = 139346, upload-time = "2025-10-08T19:24:22.392Z" }, +] + +[[package]] +name = "botocore" +version = "1.40.48" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/20/c71c9417bd2fc37bfef48df1ee8f1178b832ee3c12c4459663dfeb2c00d4/botocore-1.40.48.tar.gz", hash = "sha256:18bed348ce707aa896065b424f36a0b8d542fa6810e9165618e105b1abf34e7e", size = 14403422, upload-time = "2025-10-08T19:24:13.13Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/da/1f1427b166880c7820ac362eee7da62f6e24e246c60ea9f0d72d77296ce2/botocore-1.40.48-py3-none-any.whl", hash = "sha256:34795305bb5aa670befcbdc936fd144a0af5db5323d78e7245dbd6aa246bf3db", size = 14073863, upload-time = "2025-10-08T19:24:09.933Z" }, +] + +[[package]] +name = "cachetools" +version = "6.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/61/e4fad8155db4a04bfb4734c7c8ff0882f078f24294d42798b3568eb63bff/cachetools-6.2.0.tar.gz", hash = "sha256:38b328c0889450f05f5e120f56ab68c8abaf424e1275522b138ffc93253f7e32", size = 30988, upload-time = "2025-08-25T18:57:30.924Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/56/3124f61d37a7a4e7cc96afc5492c78ba0cb551151e530b54669ddd1436ef/cachetools-6.2.0-py3-none-any.whl", hash = "sha256:1c76a8960c0041fcc21097e357f882197c79da0dbff766e7317890a65d7d8ba6", size = 11276, upload-time = "2025-08-25T18:57:29.684Z" }, +] + +[[package]] +name = "certifi" +version = "2025.10.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", size = 164519, upload-time = "2025-10-05T04:12:15.808Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286, upload-time = "2025-10-05T04:12:14.03Z" }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "python_full_version < '3.13' or platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, +] + +[[package]] +name = "click" +version = "8.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, +] + +[[package]] +name = "clickhouse-connect" +version = "0.15.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "lz4" }, + { name = "pytz" }, + { name = "urllib3" }, + { name = "zstandard" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a5/b1/a17eb4409e2741286ccdac06b6ea15db178cdf1f0ed997bbf9ad3448f78e/clickhouse_connect-0.15.1.tar.gz", hash = "sha256:f2aaf5fc0bb3098c24f0d8ca7e4ecbe605a26957481dfca2c8cef9d1fad7b7ca", size = 126840, upload-time = "2026-03-30T18:58:31.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/b6/d0881ac34617b13ad555a4749aae042e0242bedbf8a258373719089885cd/clickhouse_connect-0.15.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0bef871fb9803ae82b4dc1f797b6e784de0a4dec351591191a0c1a6008548284", size = 287187, upload-time = "2026-03-30T18:57:18.962Z" }, + { url = "https://files.pythonhosted.org/packages/d6/6e/27823c38e54247ea22d96b3f4fde32831a10e5203761c0e2893bc2fc587f/clickhouse_connect-0.15.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:df93fa024d6ed46dbc3182b6202180be4cf2bbe9c331dcb21f85963b1b3fd1e5", size = 278086, upload-time = "2026-03-30T18:57:20.104Z" }, + { url = "https://files.pythonhosted.org/packages/6a/88/f1096e8b4f08e628674490e5d186c7bf09174bbbc5fefa530e28e6b39da3/clickhouse_connect-0.15.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6e98c0cf53db3b24dc0ff9f522fcf13205b1d191c632567d1744fbd4671741f", size = 1122144, upload-time = "2026-03-30T18:57:21.205Z" }, + { url = "https://files.pythonhosted.org/packages/af/e5/027f8b94b54a39dcdf9b314a7cd66cb882d8ba166efc584908997c6d5acb/clickhouse_connect-0.15.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bf70933ab860bd2f0a872db624603706bed400c915c7aeef382956cf8ebbdf3", size = 1138503, upload-time = "2026-03-30T18:57:22.554Z" }, + { url = "https://files.pythonhosted.org/packages/cb/46/a830bcb46f0081630a88cb932c29804553728645c17fd1cff874fe71b1ba/clickhouse_connect-0.15.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60aa8c9c775d22db324260265f4c656f803fbc71de9193ef83cf8d8d0ef6ab9a", size = 1101890, upload-time = "2026-03-30T18:57:23.788Z" }, + { url = "https://files.pythonhosted.org/packages/4c/05/91cf7cc817ff91bc96f1e2afc84346b42e88831c9c0a7fd56e78907b5320/clickhouse_connect-0.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5462bad97d97919a4ed230e2ef28d0b76bec0354a343218647830aac7744a43b", size = 1133723, upload-time = "2026-03-30T18:57:25.105Z" }, + { url = "https://files.pythonhosted.org/packages/d7/b0/e7a71b96b7bc1df6bbacf9fa71f0cc3b8f195f58386535b72aa92304b1fb/clickhouse_connect-0.15.1-cp312-cp312-win32.whl", hash = "sha256:e1a157205efd47884c22bfe061fc6f8c9aea844929ee755c47b446093805d21a", size = 257279, upload-time = "2026-03-30T18:57:26.288Z" }, + { url = "https://files.pythonhosted.org/packages/b9/03/0ef116ef0efc6861d6e9674419709b9873603f330f95853220a145748576/clickhouse_connect-0.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:5de299ada0f7eb9090bb5a6304d8d78163d4d9cc8eb04d8f552bfb82bafb61d5", size = 275916, upload-time = "2026-03-30T18:57:27.372Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/1c62f55439287999049ddb650fffcc0898ff7639865239d8e414984c7c6b/clickhouse_connect-0.15.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:08df7857ecd2e345abbbdfc54d80fa060732cf75c953940355140af9a73b730a", size = 285254, upload-time = "2026-03-30T18:57:28.765Z" }, + { url = "https://files.pythonhosted.org/packages/41/eb/00cf4967be5553b5eca53fbea491a0860816e8f867005d4a3c60b280595c/clickhouse_connect-0.15.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d3fca3e0781b664556690decc788e7d25691043bf67a0d241e9c29233a2990d5", size = 276341, upload-time = "2026-03-30T18:57:29.895Z" }, + { url = "https://files.pythonhosted.org/packages/19/d3/a3c9ce572d3766bfd44626e40ad94539e86516f0a4821417d728e1c01c4e/clickhouse_connect-0.15.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fa01fdb92db6bf72cb9509eecd0a0057a4558a4f40c02eebffbc2d61b644620e", size = 1089774, upload-time = "2026-03-30T18:57:31.005Z" }, + { url = "https://files.pythonhosted.org/packages/6b/45/f10a275a5798cf90fb3a88f64f7410571bab4579cdd443d0820697f0e685/clickhouse_connect-0.15.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c12d9f2b2fc57adaf5ea267804f00e520771794641227ed5285e38fdf36557a6", size = 1110275, upload-time = "2026-03-30T18:57:32.513Z" }, + { url = "https://files.pythonhosted.org/packages/c9/c3/654107d5be702761670eaa58b6882455c428eaf4acc69e0920d87c6d5061/clickhouse_connect-0.15.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a9d1e12bf86cd96626f74d21e3ac237abcda105f55cd2e78d139197d35f86209", size = 1072017, upload-time = "2026-03-30T18:57:33.847Z" }, + { url = "https://files.pythonhosted.org/packages/90/aa/0f3b8f18761d3f8ec7f31a09b0329d19509b7b8f0760a327890ca29f0526/clickhouse_connect-0.15.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b6d107b5f964af97f25a0d1bfd59fe3510f2a646c87ad4f9ab9014bb0c66aa1c", size = 1105152, upload-time = "2026-03-30T18:57:35.204Z" }, + { url = "https://files.pythonhosted.org/packages/28/23/684f6074bf682fd31b1449125d895054af0880bb8481a2902c84e2c9e03b/clickhouse_connect-0.15.1-cp313-cp313-win32.whl", hash = "sha256:46bcebd00aff52ea5f7433e9cee1157b411dba9187f6677a18378c799c27c8aa", size = 256905, upload-time = "2026-03-30T18:57:36.555Z" }, + { url = "https://files.pythonhosted.org/packages/9c/77/39518de3dfb5da2234b2748a133d7626430aa26d7d38bb390c4d8b299cd3/clickhouse_connect-0.15.1-cp313-cp313-win_amd64.whl", hash = "sha256:4f87d283399cbda676c8765605bf60dc6559df6fd38cbb9ea07048a4b34dda26", size = 274792, upload-time = "2026-03-30T18:57:37.79Z" }, + { url = "https://files.pythonhosted.org/packages/31/de/3dda97f102ca428efa958ae8f739b1a5965d3d481ab8f271d2ef99a0c509/clickhouse_connect-0.15.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:8bb70307589099c67dfe9a973998491bc82c1af9040560b5ebab799721bb197d", size = 285678, upload-time = "2026-03-30T18:57:39.303Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d0/650f92e68751093fddcd37d511deea6af27cffe59e70f4a1fcd8da470260/clickhouse_connect-0.15.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:873d8f74eaec141f40ae060318c32353da94fdd4601f925bfd52426f3ddcd689", size = 277362, upload-time = "2026-03-30T18:57:40.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/93/a171190d5985a9dca175f8a5e93ec42f713b1b6f8867208f39598e2dbf05/clickhouse_connect-0.15.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24cdfe9b486c8f2e66f5f51b1f322d89d9eb4df29d9ebb2fa19b553065651e85", size = 1089575, upload-time = "2026-03-30T18:57:42.105Z" }, + { url = "https://files.pythonhosted.org/packages/2f/15/0444a28589ff918a5d5fad8f4484187e571e7cbd0d9290fdb32fee9a28b7/clickhouse_connect-0.15.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b456d469db994b188bb0b5afa373e8f2e5e2bf41a70a736b9ed2485a976e9ae", size = 1101302, upload-time = "2026-03-30T18:57:43.741Z" }, + { url = "https://files.pythonhosted.org/packages/65/88/73d1cfd0156698ca32b49fb0b227aa8500547f902f15df867169677d6a6a/clickhouse_connect-0.15.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:82e60e108d78e32d58a0f21570b02d3baad67ccbad6482eeb79d74a616d8a5ad", size = 1073001, upload-time = "2026-03-30T18:57:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/64/5c/3f2344ec05427d653f1da2e86e06539086fe94c42d73cc979dbeeebe07eb/clickhouse_connect-0.15.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b8236c7dd675ed13d5e96f1f9126eeb711e8c266e4a0476ebc32be8a17decb32", size = 1097680, upload-time = "2026-03-30T18:57:46.484Z" }, + { url = "https://files.pythonhosted.org/packages/fa/6a/f17a367f41d7fca804d16bad850e104f4f441ad67b5c60a07f5889607421/clickhouse_connect-0.15.1-cp314-cp314-win32.whl", hash = "sha256:167e674dff8ac12be7796d93190b6fe9097c042940b3c41d87fe4d85970be27d", size = 260012, upload-time = "2026-03-30T18:57:48.075Z" }, + { url = "https://files.pythonhosted.org/packages/bc/43/778e55b897351881a6794b4b0168b82418675822f78bbd63d29f621b3e63/clickhouse_connect-0.15.1-cp314-cp314-win_amd64.whl", hash = "sha256:a326e2f5518d6a9d71f0895d50a3ccd8c4d5e3abb625f39330512ff3c45c6731", size = 278610, upload-time = "2026-03-30T18:57:49.565Z" }, + { url = "https://files.pythonhosted.org/packages/1d/03/dd2f196cfbcb7f826e93eff7bcec596b7327a9cb395fc5a494a9005d8f69/clickhouse_connect-0.15.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:859c718cb93780dd681f75d59ceaf4415915fa9617a5ba2de6105e291d6df3ad", size = 298561, upload-time = "2026-03-30T18:57:51.189Z" }, + { url = "https://files.pythonhosted.org/packages/13/06/cf0b76e96eb26b4e4797d3ece7f1ba1980aa7767a0b5d53e5b260186b6c4/clickhouse_connect-0.15.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:aa9890507aac52a8a5363813bb315b6867e86a97ffa08576cb934603f5bc0216", size = 293129, upload-time = "2026-03-30T18:57:52.761Z" }, + { url = "https://files.pythonhosted.org/packages/c3/7c/6c9c9f3749e25c0bd6a470c00ade9a76c4fb9aa23c04e48f75a474942d8b/clickhouse_connect-0.15.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aeb09a6f8585f3bd4d8c5bead38f3821c076e0bca08c474a7b9039732a6e2e9a", size = 1170922, upload-time = "2026-03-30T18:57:54.195Z" }, + { url = "https://files.pythonhosted.org/packages/70/78/5507826f580046cd0b0881384539983036efe5db4ccbb2e859e7eb8b0788/clickhouse_connect-0.15.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e88a31bbd9da7f4b49de39d21e8c93c8fbb5cf487071e935af0eba884681df00", size = 1149368, upload-time = "2026-03-30T18:57:55.575Z" }, + { url = "https://files.pythonhosted.org/packages/51/3e/efe0a82a8745ab0f648f1ebb305fef4a654790c22f328f9e17694b0c7979/clickhouse_connect-0.15.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:158325a06978f91a182967341188502a0761447d1e13ffa775cf017def1a3d9e", size = 1131660, upload-time = "2026-03-30T18:57:56.99Z" }, + { url = "https://files.pythonhosted.org/packages/2b/67/f6a2e23ef10d9138733d5e5122ee59f3e5e02c5d8f1a2708f644c4336b8c/clickhouse_connect-0.15.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e702b77720ae6fd501e5a52262518dddb6c705fbc122bca4567694fb0bab401f", size = 1139070, upload-time = "2026-03-30T18:57:58.4Z" }, + { url = "https://files.pythonhosted.org/packages/43/09/d87f6b9377ff19bbe95144917a6683136db77b5957ac0e2f390cbc30313a/clickhouse_connect-0.15.1-cp314-cp314t-win32.whl", hash = "sha256:b2f5174fc6001a1555fc3cb565f3b727e1b786d572df0b30d14929ae13bd3542", size = 282350, upload-time = "2026-03-30T18:58:00.192Z" }, + { url = "https://files.pythonhosted.org/packages/92/cc/8e2437de5e0a6c831e6cb2f282cd33e16bd98213a13624df0cb146a9077e/clickhouse_connect-0.15.1-cp314-cp314t-win_amd64.whl", hash = "sha256:a1266a52bf61f0420630f625c5ac87bc2d095f08321820546300a699d4300ba3", size = 306011, upload-time = "2026-03-30T18:58:02.166Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.10.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/26/d22c300112504f5f9a9fd2297ce33c35f3d353e4aeb987c8419453b2a7c2/coverage-7.10.7.tar.gz", hash = "sha256:f4ab143ab113be368a3e9b795f9cd7906c5ef407d6173fe9675a902e1fffc239", size = 827704, upload-time = "2025-09-21T20:03:56.815Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/e4/eb12450f71b542a53972d19117ea5a5cea1cab3ac9e31b0b5d498df1bd5a/coverage-7.10.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7bb3b9ddb87ef7725056572368040c32775036472d5a033679d1fa6c8dc08417", size = 218290, upload-time = "2025-09-21T20:01:36.455Z" }, + { url = "https://files.pythonhosted.org/packages/37/66/593f9be12fc19fb36711f19a5371af79a718537204d16ea1d36f16bd78d2/coverage-7.10.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:18afb24843cbc175687225cab1138c95d262337f5473512010e46831aa0c2973", size = 218515, upload-time = "2025-09-21T20:01:37.982Z" }, + { url = "https://files.pythonhosted.org/packages/66/80/4c49f7ae09cafdacc73fbc30949ffe77359635c168f4e9ff33c9ebb07838/coverage-7.10.7-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:399a0b6347bcd3822be369392932884b8216d0944049ae22925631a9b3d4ba4c", size = 250020, upload-time = "2025-09-21T20:01:39.617Z" }, + { url = "https://files.pythonhosted.org/packages/a6/90/a64aaacab3b37a17aaedd83e8000142561a29eb262cede42d94a67f7556b/coverage-7.10.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:314f2c326ded3f4b09be11bc282eb2fc861184bc95748ae67b360ac962770be7", size = 252769, upload-time = "2025-09-21T20:01:41.341Z" }, + { url = "https://files.pythonhosted.org/packages/98/2e/2dda59afd6103b342e096f246ebc5f87a3363b5412609946c120f4e7750d/coverage-7.10.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c41e71c9cfb854789dee6fc51e46743a6d138b1803fab6cb860af43265b42ea6", size = 253901, upload-time = "2025-09-21T20:01:43.042Z" }, + { url = "https://files.pythonhosted.org/packages/53/dc/8d8119c9051d50f3119bb4a75f29f1e4a6ab9415cd1fa8bf22fcc3fb3b5f/coverage-7.10.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc01f57ca26269c2c706e838f6422e2a8788e41b3e3c65e2f41148212e57cd59", size = 250413, upload-time = "2025-09-21T20:01:44.469Z" }, + { url = "https://files.pythonhosted.org/packages/98/b3/edaff9c5d79ee4d4b6d3fe046f2b1d799850425695b789d491a64225d493/coverage-7.10.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a6442c59a8ac8b85812ce33bc4d05bde3fb22321fa8294e2a5b487c3505f611b", size = 251820, upload-time = "2025-09-21T20:01:45.915Z" }, + { url = "https://files.pythonhosted.org/packages/11/25/9a0728564bb05863f7e513e5a594fe5ffef091b325437f5430e8cfb0d530/coverage-7.10.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:78a384e49f46b80fb4c901d52d92abe098e78768ed829c673fbb53c498bef73a", size = 249941, upload-time = "2025-09-21T20:01:47.296Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fd/ca2650443bfbef5b0e74373aac4df67b08180d2f184b482c41499668e258/coverage-7.10.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5e1e9802121405ede4b0133aa4340ad8186a1d2526de5b7c3eca519db7bb89fb", size = 249519, upload-time = "2025-09-21T20:01:48.73Z" }, + { url = "https://files.pythonhosted.org/packages/24/79/f692f125fb4299b6f963b0745124998ebb8e73ecdfce4ceceb06a8c6bec5/coverage-7.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d41213ea25a86f69efd1575073d34ea11aabe075604ddf3d148ecfec9e1e96a1", size = 251375, upload-time = "2025-09-21T20:01:50.529Z" }, + { url = "https://files.pythonhosted.org/packages/5e/75/61b9bbd6c7d24d896bfeec57acba78e0f8deac68e6baf2d4804f7aae1f88/coverage-7.10.7-cp312-cp312-win32.whl", hash = "sha256:77eb4c747061a6af8d0f7bdb31f1e108d172762ef579166ec84542f711d90256", size = 220699, upload-time = "2025-09-21T20:01:51.941Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f3/3bf7905288b45b075918d372498f1cf845b5b579b723c8fd17168018d5f5/coverage-7.10.7-cp312-cp312-win_amd64.whl", hash = "sha256:f51328ffe987aecf6d09f3cd9d979face89a617eacdaea43e7b3080777f647ba", size = 221512, upload-time = "2025-09-21T20:01:53.481Z" }, + { url = "https://files.pythonhosted.org/packages/5c/44/3e32dbe933979d05cf2dac5e697c8599cfe038aaf51223ab901e208d5a62/coverage-7.10.7-cp312-cp312-win_arm64.whl", hash = "sha256:bda5e34f8a75721c96085903c6f2197dc398c20ffd98df33f866a9c8fd95f4bf", size = 220147, upload-time = "2025-09-21T20:01:55.2Z" }, + { url = "https://files.pythonhosted.org/packages/9a/94/b765c1abcb613d103b64fcf10395f54d69b0ef8be6a0dd9c524384892cc7/coverage-7.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:981a651f543f2854abd3b5fcb3263aac581b18209be49863ba575de6edf4c14d", size = 218320, upload-time = "2025-09-21T20:01:56.629Z" }, + { url = "https://files.pythonhosted.org/packages/72/4f/732fff31c119bb73b35236dd333030f32c4bfe909f445b423e6c7594f9a2/coverage-7.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73ab1601f84dc804f7812dc297e93cd99381162da39c47040a827d4e8dafe63b", size = 218575, upload-time = "2025-09-21T20:01:58.203Z" }, + { url = "https://files.pythonhosted.org/packages/87/02/ae7e0af4b674be47566707777db1aa375474f02a1d64b9323e5813a6cdd5/coverage-7.10.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a8b6f03672aa6734e700bbcd65ff050fd19cddfec4b031cc8cf1c6967de5a68e", size = 249568, upload-time = "2025-09-21T20:01:59.748Z" }, + { url = "https://files.pythonhosted.org/packages/a2/77/8c6d22bf61921a59bce5471c2f1f7ac30cd4ac50aadde72b8c48d5727902/coverage-7.10.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10b6ba00ab1132a0ce4428ff68cf50a25efd6840a42cdf4239c9b99aad83be8b", size = 252174, upload-time = "2025-09-21T20:02:01.192Z" }, + { url = "https://files.pythonhosted.org/packages/b1/20/b6ea4f69bbb52dac0aebd62157ba6a9dddbfe664f5af8122dac296c3ee15/coverage-7.10.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c79124f70465a150e89340de5963f936ee97097d2ef76c869708c4248c63ca49", size = 253447, upload-time = "2025-09-21T20:02:02.701Z" }, + { url = "https://files.pythonhosted.org/packages/f9/28/4831523ba483a7f90f7b259d2018fef02cb4d5b90bc7c1505d6e5a84883c/coverage-7.10.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:69212fbccdbd5b0e39eac4067e20a4a5256609e209547d86f740d68ad4f04911", size = 249779, upload-time = "2025-09-21T20:02:04.185Z" }, + { url = "https://files.pythonhosted.org/packages/a7/9f/4331142bc98c10ca6436d2d620c3e165f31e6c58d43479985afce6f3191c/coverage-7.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7ea7c6c9d0d286d04ed3541747e6597cbe4971f22648b68248f7ddcd329207f0", size = 251604, upload-time = "2025-09-21T20:02:06.034Z" }, + { url = "https://files.pythonhosted.org/packages/ce/60/bda83b96602036b77ecf34e6393a3836365481b69f7ed7079ab85048202b/coverage-7.10.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b9be91986841a75042b3e3243d0b3cb0b2434252b977baaf0cd56e960fe1e46f", size = 249497, upload-time = "2025-09-21T20:02:07.619Z" }, + { url = "https://files.pythonhosted.org/packages/5f/af/152633ff35b2af63977edd835d8e6430f0caef27d171edf2fc76c270ef31/coverage-7.10.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b281d5eca50189325cfe1f365fafade89b14b4a78d9b40b05ddd1fc7d2a10a9c", size = 249350, upload-time = "2025-09-21T20:02:10.34Z" }, + { url = "https://files.pythonhosted.org/packages/9d/71/d92105d122bd21cebba877228990e1646d862e34a98bb3374d3fece5a794/coverage-7.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:99e4aa63097ab1118e75a848a28e40d68b08a5e19ce587891ab7fd04475e780f", size = 251111, upload-time = "2025-09-21T20:02:12.122Z" }, + { url = "https://files.pythonhosted.org/packages/a2/9e/9fdb08f4bf476c912f0c3ca292e019aab6712c93c9344a1653986c3fd305/coverage-7.10.7-cp313-cp313-win32.whl", hash = "sha256:dc7c389dce432500273eaf48f410b37886be9208b2dd5710aaf7c57fd442c698", size = 220746, upload-time = "2025-09-21T20:02:13.919Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b1/a75fd25df44eab52d1931e89980d1ada46824c7a3210be0d3c88a44aaa99/coverage-7.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:cac0fdca17b036af3881a9d2729a850b76553f3f716ccb0360ad4dbc06b3b843", size = 221541, upload-time = "2025-09-21T20:02:15.57Z" }, + { url = "https://files.pythonhosted.org/packages/14/3a/d720d7c989562a6e9a14b2c9f5f2876bdb38e9367126d118495b89c99c37/coverage-7.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:4b6f236edf6e2f9ae8fcd1332da4e791c1b6ba0dc16a2dc94590ceccb482e546", size = 220170, upload-time = "2025-09-21T20:02:17.395Z" }, + { url = "https://files.pythonhosted.org/packages/bb/22/e04514bf2a735d8b0add31d2b4ab636fc02370730787c576bb995390d2d5/coverage-7.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a0ec07fd264d0745ee396b666d47cef20875f4ff2375d7c4f58235886cc1ef0c", size = 219029, upload-time = "2025-09-21T20:02:18.936Z" }, + { url = "https://files.pythonhosted.org/packages/11/0b/91128e099035ece15da3445d9015e4b4153a6059403452d324cbb0a575fa/coverage-7.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd5e856ebb7bfb7672b0086846db5afb4567a7b9714b8a0ebafd211ec7ce6a15", size = 219259, upload-time = "2025-09-21T20:02:20.44Z" }, + { url = "https://files.pythonhosted.org/packages/8b/51/66420081e72801536a091a0c8f8c1f88a5c4bf7b9b1bdc6222c7afe6dc9b/coverage-7.10.7-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f57b2a3c8353d3e04acf75b3fed57ba41f5c0646bbf1d10c7c282291c97936b4", size = 260592, upload-time = "2025-09-21T20:02:22.313Z" }, + { url = "https://files.pythonhosted.org/packages/5d/22/9b8d458c2881b22df3db5bb3e7369e63d527d986decb6c11a591ba2364f7/coverage-7.10.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ef2319dd15a0b009667301a3f84452a4dc6fddfd06b0c5c53ea472d3989fbf0", size = 262768, upload-time = "2025-09-21T20:02:24.287Z" }, + { url = "https://files.pythonhosted.org/packages/f7/08/16bee2c433e60913c610ea200b276e8eeef084b0d200bdcff69920bd5828/coverage-7.10.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83082a57783239717ceb0ad584de3c69cf581b2a95ed6bf81ea66034f00401c0", size = 264995, upload-time = "2025-09-21T20:02:26.133Z" }, + { url = "https://files.pythonhosted.org/packages/20/9d/e53eb9771d154859b084b90201e5221bca7674ba449a17c101a5031d4054/coverage-7.10.7-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:50aa94fb1fb9a397eaa19c0d5ec15a5edd03a47bf1a3a6111a16b36e190cff65", size = 259546, upload-time = "2025-09-21T20:02:27.716Z" }, + { url = "https://files.pythonhosted.org/packages/ad/b0/69bc7050f8d4e56a89fb550a1577d5d0d1db2278106f6f626464067b3817/coverage-7.10.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2120043f147bebb41c85b97ac45dd173595ff14f2a584f2963891cbcc3091541", size = 262544, upload-time = "2025-09-21T20:02:29.216Z" }, + { url = "https://files.pythonhosted.org/packages/ef/4b/2514b060dbd1bc0aaf23b852c14bb5818f244c664cb16517feff6bb3a5ab/coverage-7.10.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2fafd773231dd0378fdba66d339f84904a8e57a262f583530f4f156ab83863e6", size = 260308, upload-time = "2025-09-21T20:02:31.226Z" }, + { url = "https://files.pythonhosted.org/packages/54/78/7ba2175007c246d75e496f64c06e94122bdb914790a1285d627a918bd271/coverage-7.10.7-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:0b944ee8459f515f28b851728ad224fa2d068f1513ef6b7ff1efafeb2185f999", size = 258920, upload-time = "2025-09-21T20:02:32.823Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b3/fac9f7abbc841409b9a410309d73bfa6cfb2e51c3fada738cb607ce174f8/coverage-7.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4b583b97ab2e3efe1b3e75248a9b333bd3f8b0b1b8e5b45578e05e5850dfb2c2", size = 261434, upload-time = "2025-09-21T20:02:34.86Z" }, + { url = "https://files.pythonhosted.org/packages/ee/51/a03bec00d37faaa891b3ff7387192cef20f01604e5283a5fabc95346befa/coverage-7.10.7-cp313-cp313t-win32.whl", hash = "sha256:2a78cd46550081a7909b3329e2266204d584866e8d97b898cd7fb5ac8d888b1a", size = 221403, upload-time = "2025-09-21T20:02:37.034Z" }, + { url = "https://files.pythonhosted.org/packages/53/22/3cf25d614e64bf6d8e59c7c669b20d6d940bb337bdee5900b9ca41c820bb/coverage-7.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:33a5e6396ab684cb43dc7befa386258acb2d7fae7f67330ebb85ba4ea27938eb", size = 222469, upload-time = "2025-09-21T20:02:39.011Z" }, + { url = "https://files.pythonhosted.org/packages/49/a1/00164f6d30d8a01c3c9c48418a7a5be394de5349b421b9ee019f380df2a0/coverage-7.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:86b0e7308289ddde73d863b7683f596d8d21c7d8664ce1dee061d0bcf3fbb4bb", size = 220731, upload-time = "2025-09-21T20:02:40.939Z" }, + { url = "https://files.pythonhosted.org/packages/23/9c/5844ab4ca6a4dd97a1850e030a15ec7d292b5c5cb93082979225126e35dd/coverage-7.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b06f260b16ead11643a5a9f955bd4b5fd76c1a4c6796aeade8520095b75de520", size = 218302, upload-time = "2025-09-21T20:02:42.527Z" }, + { url = "https://files.pythonhosted.org/packages/f0/89/673f6514b0961d1f0e20ddc242e9342f6da21eaba3489901b565c0689f34/coverage-7.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:212f8f2e0612778f09c55dd4872cb1f64a1f2b074393d139278ce902064d5b32", size = 218578, upload-time = "2025-09-21T20:02:44.468Z" }, + { url = "https://files.pythonhosted.org/packages/05/e8/261cae479e85232828fb17ad536765c88dd818c8470aca690b0ac6feeaa3/coverage-7.10.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3445258bcded7d4aa630ab8296dea4d3f15a255588dd535f980c193ab6b95f3f", size = 249629, upload-time = "2025-09-21T20:02:46.503Z" }, + { url = "https://files.pythonhosted.org/packages/82/62/14ed6546d0207e6eda876434e3e8475a3e9adbe32110ce896c9e0c06bb9a/coverage-7.10.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb45474711ba385c46a0bfe696c695a929ae69ac636cda8f532be9e8c93d720a", size = 252162, upload-time = "2025-09-21T20:02:48.689Z" }, + { url = "https://files.pythonhosted.org/packages/ff/49/07f00db9ac6478e4358165a08fb41b469a1b053212e8a00cb02f0d27a05f/coverage-7.10.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:813922f35bd800dca9994c5971883cbc0d291128a5de6b167c7aa697fcf59360", size = 253517, upload-time = "2025-09-21T20:02:50.31Z" }, + { url = "https://files.pythonhosted.org/packages/a2/59/c5201c62dbf165dfbc91460f6dbbaa85a8b82cfa6131ac45d6c1bfb52deb/coverage-7.10.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c1b03552081b2a4423091d6fb3787265b8f86af404cff98d1b5342713bdd69", size = 249632, upload-time = "2025-09-21T20:02:51.971Z" }, + { url = "https://files.pythonhosted.org/packages/07/ae/5920097195291a51fb00b3a70b9bbd2edbfe3c84876a1762bd1ef1565ebc/coverage-7.10.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:cc87dd1b6eaf0b848eebb1c86469b9f72a1891cb42ac7adcfbce75eadb13dd14", size = 251520, upload-time = "2025-09-21T20:02:53.858Z" }, + { url = "https://files.pythonhosted.org/packages/b9/3c/a815dde77a2981f5743a60b63df31cb322c944843e57dbd579326625a413/coverage-7.10.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:39508ffda4f343c35f3236fe8d1a6634a51f4581226a1262769d7f970e73bffe", size = 249455, upload-time = "2025-09-21T20:02:55.807Z" }, + { url = "https://files.pythonhosted.org/packages/aa/99/f5cdd8421ea656abefb6c0ce92556709db2265c41e8f9fc6c8ae0f7824c9/coverage-7.10.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:925a1edf3d810537c5a3abe78ec5530160c5f9a26b1f4270b40e62cc79304a1e", size = 249287, upload-time = "2025-09-21T20:02:57.784Z" }, + { url = "https://files.pythonhosted.org/packages/c3/7a/e9a2da6a1fc5d007dd51fca083a663ab930a8c4d149c087732a5dbaa0029/coverage-7.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2c8b9a0636f94c43cd3576811e05b89aa9bc2d0a85137affc544ae5cb0e4bfbd", size = 250946, upload-time = "2025-09-21T20:02:59.431Z" }, + { url = "https://files.pythonhosted.org/packages/ef/5b/0b5799aa30380a949005a353715095d6d1da81927d6dbed5def2200a4e25/coverage-7.10.7-cp314-cp314-win32.whl", hash = "sha256:b7b8288eb7cdd268b0304632da8cb0bb93fadcfec2fe5712f7b9cc8f4d487be2", size = 221009, upload-time = "2025-09-21T20:03:01.324Z" }, + { url = "https://files.pythonhosted.org/packages/da/b0/e802fbb6eb746de006490abc9bb554b708918b6774b722bb3a0e6aa1b7de/coverage-7.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:1ca6db7c8807fb9e755d0379ccc39017ce0a84dcd26d14b5a03b78563776f681", size = 221804, upload-time = "2025-09-21T20:03:03.4Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e8/71d0c8e374e31f39e3389bb0bd19e527d46f00ea8571ec7ec8fd261d8b44/coverage-7.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:097c1591f5af4496226d5783d036bf6fd6cd0cbc132e071b33861de756efb880", size = 220384, upload-time = "2025-09-21T20:03:05.111Z" }, + { url = "https://files.pythonhosted.org/packages/62/09/9a5608d319fa3eba7a2019addeacb8c746fb50872b57a724c9f79f146969/coverage-7.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a62c6ef0d50e6de320c270ff91d9dd0a05e7250cac2a800b7784bae474506e63", size = 219047, upload-time = "2025-09-21T20:03:06.795Z" }, + { url = "https://files.pythonhosted.org/packages/f5/6f/f58d46f33db9f2e3647b2d0764704548c184e6f5e014bef528b7f979ef84/coverage-7.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9fa6e4dd51fe15d8738708a973470f67a855ca50002294852e9571cdbd9433f2", size = 219266, upload-time = "2025-09-21T20:03:08.495Z" }, + { url = "https://files.pythonhosted.org/packages/74/5c/183ffc817ba68e0b443b8c934c8795553eb0c14573813415bd59941ee165/coverage-7.10.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8fb190658865565c549b6b4706856d6a7b09302c797eb2cf8e7fe9dabb043f0d", size = 260767, upload-time = "2025-09-21T20:03:10.172Z" }, + { url = "https://files.pythonhosted.org/packages/0f/48/71a8abe9c1ad7e97548835e3cc1adbf361e743e9d60310c5f75c9e7bf847/coverage-7.10.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:affef7c76a9ef259187ef31599a9260330e0335a3011732c4b9effa01e1cd6e0", size = 262931, upload-time = "2025-09-21T20:03:11.861Z" }, + { url = "https://files.pythonhosted.org/packages/84/fd/193a8fb132acfc0a901f72020e54be5e48021e1575bb327d8ee1097a28fd/coverage-7.10.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e16e07d85ca0cf8bafe5f5d23a0b850064e8e945d5677492b06bbe6f09cc699", size = 265186, upload-time = "2025-09-21T20:03:13.539Z" }, + { url = "https://files.pythonhosted.org/packages/b1/8f/74ecc30607dd95ad50e3034221113ccb1c6d4e8085cc761134782995daae/coverage-7.10.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:03ffc58aacdf65d2a82bbeb1ffe4d01ead4017a21bfd0454983b88ca73af94b9", size = 259470, upload-time = "2025-09-21T20:03:15.584Z" }, + { url = "https://files.pythonhosted.org/packages/0f/55/79ff53a769f20d71b07023ea115c9167c0bb56f281320520cf64c5298a96/coverage-7.10.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1b4fd784344d4e52647fd7857b2af5b3fbe6c239b0b5fa63e94eb67320770e0f", size = 262626, upload-time = "2025-09-21T20:03:17.673Z" }, + { url = "https://files.pythonhosted.org/packages/88/e2/dac66c140009b61ac3fc13af673a574b00c16efdf04f9b5c740703e953c0/coverage-7.10.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0ebbaddb2c19b71912c6f2518e791aa8b9f054985a0769bdb3a53ebbc765c6a1", size = 260386, upload-time = "2025-09-21T20:03:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/a2/f1/f48f645e3f33bb9ca8a496bc4a9671b52f2f353146233ebd7c1df6160440/coverage-7.10.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a2d9a3b260cc1d1dbdb1c582e63ddcf5363426a1a68faa0f5da28d8ee3c722a0", size = 258852, upload-time = "2025-09-21T20:03:21.007Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3b/8442618972c51a7affeead957995cfa8323c0c9bcf8fa5a027421f720ff4/coverage-7.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a3cc8638b2480865eaa3926d192e64ce6c51e3d29c849e09d5b4ad95efae5399", size = 261534, upload-time = "2025-09-21T20:03:23.12Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dc/101f3fa3a45146db0cb03f5b4376e24c0aac818309da23e2de0c75295a91/coverage-7.10.7-cp314-cp314t-win32.whl", hash = "sha256:67f8c5cbcd3deb7a60b3345dffc89a961a484ed0af1f6f73de91705cc6e31235", size = 221784, upload-time = "2025-09-21T20:03:24.769Z" }, + { url = "https://files.pythonhosted.org/packages/4c/a1/74c51803fc70a8a40d7346660379e144be772bab4ac7bb6e6b905152345c/coverage-7.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e1ed71194ef6dea7ed2d5cb5f7243d4bcd334bfb63e59878519be558078f848d", size = 222905, upload-time = "2025-09-21T20:03:26.93Z" }, + { url = "https://files.pythonhosted.org/packages/12/65/f116a6d2127df30bcafbceef0302d8a64ba87488bf6f73a6d8eebf060873/coverage-7.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:7fe650342addd8524ca63d77b2362b02345e5f1a093266787d210c70a50b471a", size = 220922, upload-time = "2025-09-21T20:03:28.672Z" }, + { url = "https://files.pythonhosted.org/packages/ec/16/114df1c291c22cac3b0c127a73e0af5c12ed7bbb6558d310429a0ae24023/coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260", size = 209952, upload-time = "2025-09-21T20:03:53.918Z" }, +] + +[[package]] +name = "cryptography" +version = "45.0.7" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and platform_python_implementation != 'PyPy'", +] +dependencies = [ + { name = "cffi", marker = "python_full_version >= '3.14' and platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/35/c495bffc2056f2dadb32434f1feedd79abde2a7f8363e1974afa9c33c7e2/cryptography-45.0.7.tar.gz", hash = "sha256:4b1654dfc64ea479c242508eb8c724044f1e964a47d1d1cacc5132292d851971", size = 744980, upload-time = "2025-09-01T11:15:03.146Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/91/925c0ac74362172ae4516000fe877912e33b5983df735ff290c653de4913/cryptography-45.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3be4f21c6245930688bd9e162829480de027f8bf962ede33d4f8ba7d67a00cee", size = 7041105, upload-time = "2025-09-01T11:13:59.684Z" }, + { url = "https://files.pythonhosted.org/packages/fc/63/43641c5acce3a6105cf8bd5baeceeb1846bb63067d26dae3e5db59f1513a/cryptography-45.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:67285f8a611b0ebc0857ced2081e30302909f571a46bfa7a3cc0ad303fe015c6", size = 4205799, upload-time = "2025-09-01T11:14:02.517Z" }, + { url = "https://files.pythonhosted.org/packages/bc/29/c238dd9107f10bfde09a4d1c52fd38828b1aa353ced11f358b5dd2507d24/cryptography-45.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:577470e39e60a6cd7780793202e63536026d9b8641de011ed9d8174da9ca5339", size = 4430504, upload-time = "2025-09-01T11:14:04.522Z" }, + { url = "https://files.pythonhosted.org/packages/62/62/24203e7cbcc9bd7c94739428cd30680b18ae6b18377ae66075c8e4771b1b/cryptography-45.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4bd3e5c4b9682bc112d634f2c6ccc6736ed3635fc3319ac2bb11d768cc5a00d8", size = 4209542, upload-time = "2025-09-01T11:14:06.309Z" }, + { url = "https://files.pythonhosted.org/packages/cd/e3/e7de4771a08620eef2389b86cd87a2c50326827dea5528feb70595439ce4/cryptography-45.0.7-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:465ccac9d70115cd4de7186e60cfe989de73f7bb23e8a7aa45af18f7412e75bf", size = 3889244, upload-time = "2025-09-01T11:14:08.152Z" }, + { url = "https://files.pythonhosted.org/packages/96/b8/bca71059e79a0bb2f8e4ec61d9c205fbe97876318566cde3b5092529faa9/cryptography-45.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:16ede8a4f7929b4b7ff3642eba2bf79aa1d71f24ab6ee443935c0d269b6bc513", size = 4461975, upload-time = "2025-09-01T11:14:09.755Z" }, + { url = "https://files.pythonhosted.org/packages/58/67/3f5b26937fe1218c40e95ef4ff8d23c8dc05aa950d54200cc7ea5fb58d28/cryptography-45.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8978132287a9d3ad6b54fcd1e08548033cc09dc6aacacb6c004c73c3eb5d3ac3", size = 4209082, upload-time = "2025-09-01T11:14:11.229Z" }, + { url = "https://files.pythonhosted.org/packages/0e/e4/b3e68a4ac363406a56cf7b741eeb80d05284d8c60ee1a55cdc7587e2a553/cryptography-45.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b6a0e535baec27b528cb07a119f321ac024592388c5681a5ced167ae98e9fff3", size = 4460397, upload-time = "2025-09-01T11:14:12.924Z" }, + { url = "https://files.pythonhosted.org/packages/22/49/2c93f3cd4e3efc8cb22b02678c1fad691cff9dd71bb889e030d100acbfe0/cryptography-45.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a24ee598d10befaec178efdff6054bc4d7e883f615bfbcd08126a0f4931c83a6", size = 4337244, upload-time = "2025-09-01T11:14:14.431Z" }, + { url = "https://files.pythonhosted.org/packages/04/19/030f400de0bccccc09aa262706d90f2ec23d56bc4eb4f4e8268d0ddf3fb8/cryptography-45.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa26fa54c0a9384c27fcdc905a2fb7d60ac6e47d14bc2692145f2b3b1e2cfdbd", size = 4568862, upload-time = "2025-09-01T11:14:16.185Z" }, + { url = "https://files.pythonhosted.org/packages/29/56/3034a3a353efa65116fa20eb3c990a8c9f0d3db4085429040a7eef9ada5f/cryptography-45.0.7-cp311-abi3-win32.whl", hash = "sha256:bef32a5e327bd8e5af915d3416ffefdbe65ed975b646b3805be81b23580b57b8", size = 2936578, upload-time = "2025-09-01T11:14:17.638Z" }, + { url = "https://files.pythonhosted.org/packages/b3/61/0ab90f421c6194705a99d0fa9f6ee2045d916e4455fdbb095a9c2c9a520f/cryptography-45.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:3808e6b2e5f0b46d981c24d79648e5c25c35e59902ea4391a0dcb3e667bf7443", size = 3405400, upload-time = "2025-09-01T11:14:18.958Z" }, + { url = "https://files.pythonhosted.org/packages/63/e8/c436233ddf19c5f15b25ace33979a9dd2e7aa1a59209a0ee8554179f1cc0/cryptography-45.0.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bfb4c801f65dd61cedfc61a83732327fafbac55a47282e6f26f073ca7a41c3b2", size = 7021824, upload-time = "2025-09-01T11:14:20.954Z" }, + { url = "https://files.pythonhosted.org/packages/bc/4c/8f57f2500d0ccd2675c5d0cc462095adf3faa8c52294ba085c036befb901/cryptography-45.0.7-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:81823935e2f8d476707e85a78a405953a03ef7b7b4f55f93f7c2d9680e5e0691", size = 4202233, upload-time = "2025-09-01T11:14:22.454Z" }, + { url = "https://files.pythonhosted.org/packages/eb/ac/59b7790b4ccaed739fc44775ce4645c9b8ce54cbec53edf16c74fd80cb2b/cryptography-45.0.7-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3994c809c17fc570c2af12c9b840d7cea85a9fd3e5c0e0491f4fa3c029216d59", size = 4423075, upload-time = "2025-09-01T11:14:24.287Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/d4f07ea21434bf891faa088a6ac15d6d98093a66e75e30ad08e88aa2b9ba/cryptography-45.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dad43797959a74103cb59c5dac71409f9c27d34c8a05921341fb64ea8ccb1dd4", size = 4204517, upload-time = "2025-09-01T11:14:25.679Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ac/924a723299848b4c741c1059752c7cfe09473b6fd77d2920398fc26bfb53/cryptography-45.0.7-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ce7a453385e4c4693985b4a4a3533e041558851eae061a58a5405363b098fcd3", size = 3882893, upload-time = "2025-09-01T11:14:27.1Z" }, + { url = "https://files.pythonhosted.org/packages/83/dc/4dab2ff0a871cc2d81d3ae6d780991c0192b259c35e4d83fe1de18b20c70/cryptography-45.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b04f85ac3a90c227b6e5890acb0edbaf3140938dbecf07bff618bf3638578cf1", size = 4450132, upload-time = "2025-09-01T11:14:28.58Z" }, + { url = "https://files.pythonhosted.org/packages/12/dd/b2882b65db8fc944585d7fb00d67cf84a9cef4e77d9ba8f69082e911d0de/cryptography-45.0.7-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:48c41a44ef8b8c2e80ca4527ee81daa4c527df3ecbc9423c41a420a9559d0e27", size = 4204086, upload-time = "2025-09-01T11:14:30.572Z" }, + { url = "https://files.pythonhosted.org/packages/5d/fa/1d5745d878048699b8eb87c984d4ccc5da4f5008dfd3ad7a94040caca23a/cryptography-45.0.7-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f3df7b3d0f91b88b2106031fd995802a2e9ae13e02c36c1fc075b43f420f3a17", size = 4449383, upload-time = "2025-09-01T11:14:32.046Z" }, + { url = "https://files.pythonhosted.org/packages/36/8b/fc61f87931bc030598e1876c45b936867bb72777eac693e905ab89832670/cryptography-45.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dd342f085542f6eb894ca00ef70236ea46070c8a13824c6bde0dfdcd36065b9b", size = 4332186, upload-time = "2025-09-01T11:14:33.95Z" }, + { url = "https://files.pythonhosted.org/packages/0b/11/09700ddad7443ccb11d674efdbe9a832b4455dc1f16566d9bd3834922ce5/cryptography-45.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1993a1bb7e4eccfb922b6cd414f072e08ff5816702a0bdb8941c247a6b1b287c", size = 4561639, upload-time = "2025-09-01T11:14:35.343Z" }, + { url = "https://files.pythonhosted.org/packages/71/ed/8f4c1337e9d3b94d8e50ae0b08ad0304a5709d483bfcadfcc77a23dbcb52/cryptography-45.0.7-cp37-abi3-win32.whl", hash = "sha256:18fcf70f243fe07252dcb1b268a687f2358025ce32f9f88028ca5c364b123ef5", size = 2926552, upload-time = "2025-09-01T11:14:36.929Z" }, + { url = "https://files.pythonhosted.org/packages/bc/ff/026513ecad58dacd45d1d24ebe52b852165a26e287177de1d545325c0c25/cryptography-45.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:7285a89df4900ed3bfaad5679b1e668cb4b38a8de1ccbfc84b05f34512da0a90", size = 3392742, upload-time = "2025-09-01T11:14:38.368Z" }, +] + +[[package]] +name = "cryptography" +version = "46.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.13.*' and platform_python_implementation != 'PyPy'", + "python_full_version >= '3.14' and platform_python_implementation == 'PyPy'", + "python_full_version == '3.13.*' and platform_python_implementation == 'PyPy'", + "python_full_version < '3.13'", +] +dependencies = [ + { name = "cffi", marker = "python_full_version < '3.14' and platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/ee/04cd4314db26ffc951c1ea90bde30dd226880ab9343759d7abbecef377ee/cryptography-46.0.0.tar.gz", hash = "sha256:99f64a6d15f19f3afd78720ad2978f6d8d4c68cd4eb600fab82ab1a7c2071dca", size = 749158, upload-time = "2025-09-16T21:07:49.091Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/bd/3e935ca6e87dc4969683f5dd9e49adaf2cb5734253d93317b6b346e0bd33/cryptography-46.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:c9c4121f9a41cc3d02164541d986f59be31548ad355a5c96ac50703003c50fb7", size = 7285468, upload-time = "2025-09-16T21:05:52.026Z" }, + { url = "https://files.pythonhosted.org/packages/c7/ee/dd17f412ce64b347871d7752657c5084940d42af4d9c25b1b91c7ee53362/cryptography-46.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4f70cbade61a16f5e238c4b0eb4e258d177a2fcb59aa0aae1236594f7b0ae338", size = 4308218, upload-time = "2025-09-16T21:05:55.653Z" }, + { url = "https://files.pythonhosted.org/packages/2f/53/f0b865a971e4e8b3e90e648b6f828950dea4c221bb699421e82ef45f0ef9/cryptography-46.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d1eccae15d5c28c74b2bea228775c63ac5b6c36eedb574e002440c0bc28750d3", size = 4571982, upload-time = "2025-09-16T21:05:57.322Z" }, + { url = "https://files.pythonhosted.org/packages/d4/c8/035be5fd63a98284fd74df9e04156f9fed7aa45cef41feceb0d06cbdadd0/cryptography-46.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1b4fba84166d906a22027f0d958e42f3a4dbbb19c28ea71f0fb7812380b04e3c", size = 4307996, upload-time = "2025-09-16T21:05:59.043Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4a/dbb6d7d0a48b95984e2d4caf0a4c7d6606cea5d30241d984c0c02b47f1b6/cryptography-46.0.0-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:523153480d7575a169933f083eb47b1edd5fef45d87b026737de74ffeb300f69", size = 4015692, upload-time = "2025-09-16T21:06:01.324Z" }, + { url = "https://files.pythonhosted.org/packages/65/48/aafcffdde716f6061864e56a0a5908f08dcb8523dab436228957c8ebd5df/cryptography-46.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:f09a3a108223e319168b7557810596631a8cb864657b0c16ed7a6017f0be9433", size = 4982192, upload-time = "2025-09-16T21:06:03.367Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ab/1e73cfc181afc3054a09e5e8f7753a8fba254592ff50b735d7456d197353/cryptography-46.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c1f6ccd6f2eef3b2eb52837f0463e853501e45a916b3fc42e5d93cf244a4b97b", size = 4603944, upload-time = "2025-09-16T21:06:05.29Z" }, + { url = "https://files.pythonhosted.org/packages/3a/02/d71dac90b77c606c90c366571edf264dc8bd37cf836e7f902253cbf5aa77/cryptography-46.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:80a548a5862d6912a45557a101092cd6c64ae1475b82cef50ee305d14a75f598", size = 4308149, upload-time = "2025-09-16T21:06:07.006Z" }, + { url = "https://files.pythonhosted.org/packages/29/e6/4dcb67fdc6addf4e319a99c4bed25776cb691f3aa6e0c4646474748816c6/cryptography-46.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:6c39fd5cd9b7526afa69d64b5e5645a06e1b904f342584b3885254400b63f1b3", size = 4947449, upload-time = "2025-09-16T21:06:11.244Z" }, + { url = "https://files.pythonhosted.org/packages/26/04/91e3fad8ee33aa87815c8f25563f176a58da676c2b14757a4d3b19f0253c/cryptography-46.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:d5c0cbb2fb522f7e39b59a5482a1c9c5923b7c506cfe96a1b8e7368c31617ac0", size = 4603549, upload-time = "2025-09-16T21:06:13.268Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6e/caf4efadcc8f593cbaacfbb04778f78b6d0dac287b45cec25e5054de38b7/cryptography-46.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6d8945bc120dcd90ae39aa841afddaeafc5f2e832809dc54fb906e3db829dfdc", size = 4435976, upload-time = "2025-09-16T21:06:16.514Z" }, + { url = "https://files.pythonhosted.org/packages/c1/c0/704710f349db25c5b91965c3662d5a758011b2511408d9451126429b6cd6/cryptography-46.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:88c09da8a94ac27798f6b62de6968ac78bb94805b5d272dbcfd5fdc8c566999f", size = 4709447, upload-time = "2025-09-16T21:06:19.246Z" }, + { url = "https://files.pythonhosted.org/packages/91/5e/ff63bfd27b75adaf75cc2398de28a0b08105f9d7f8193f3b9b071e38e8b9/cryptography-46.0.0-cp311-abi3-win32.whl", hash = "sha256:3738f50215211cee1974193a1809348d33893696ce119968932ea117bcbc9b1d", size = 3058317, upload-time = "2025-09-16T21:06:21.466Z" }, + { url = "https://files.pythonhosted.org/packages/46/47/4caf35014c4551dd0b43aa6c2e250161f7ffcb9c3918c9e075785047d5d2/cryptography-46.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:bbaa5eef3c19c66613317dc61e211b48d5f550db009c45e1c28b59d5a9b7812a", size = 3523891, upload-time = "2025-09-16T21:06:23.856Z" }, + { url = "https://files.pythonhosted.org/packages/98/66/6a0cafb3084a854acf808fccf756cbc9b835d1b99fb82c4a15e2e2ffb404/cryptography-46.0.0-cp311-abi3-win_arm64.whl", hash = "sha256:16b5ac72a965ec9d1e34d9417dbce235d45fa04dac28634384e3ce40dfc66495", size = 2932145, upload-time = "2025-09-16T21:06:25.842Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/0cf967a1dc1419d5dde111bd0e22872038199f4e4655539ea6f4da5ad7f1/cryptography-46.0.0-cp314-abi3-macosx_10_9_universal2.whl", hash = "sha256:91585fc9e696abd7b3e48a463a20dda1a5c0eeeca4ba60fa4205a79527694390", size = 7203952, upload-time = "2025-09-16T21:06:28.21Z" }, + { url = "https://files.pythonhosted.org/packages/9c/9e/d20925af5f0484c5049cf7254c91b79776a9b555af04493de6bdd419b495/cryptography-46.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:65e9117ebed5b16b28154ed36b164c20021f3a480e9cbb4b4a2a59b95e74c25d", size = 4293519, upload-time = "2025-09-16T21:06:30.143Z" }, + { url = "https://files.pythonhosted.org/packages/5f/b9/07aec6b183ef0054b5f826ae43f0b4db34c50b56aff18f67babdcc2642a3/cryptography-46.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:da7f93551d39d462263b6b5c9056c49f780b9200bf9fc2656d7c88c7bdb9b363", size = 4545583, upload-time = "2025-09-16T21:06:31.914Z" }, + { url = "https://files.pythonhosted.org/packages/39/4a/7d25158be8c607e2b9ebda49be762404d675b47df335d0d2a3b979d80213/cryptography-46.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:be7479f9504bfb46628544ec7cb4637fe6af8b70445d4455fbb9c395ad9b7290", size = 4299196, upload-time = "2025-09-16T21:06:33.724Z" }, + { url = "https://files.pythonhosted.org/packages/15/3f/65c8753c0dbebe769cc9f9d87d52bce8b74e850ef2818c59bfc7e4248663/cryptography-46.0.0-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f85e6a7d42ad60024fa1347b1d4ef82c4df517a4deb7f829d301f1a92ded038c", size = 3994419, upload-time = "2025-09-16T21:06:35.877Z" }, + { url = "https://files.pythonhosted.org/packages/d5/b4/69a271873cfc333a236443c94aa07e0233bc36b384e182da2263703b5759/cryptography-46.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:d349af4d76a93562f1dce4d983a4a34d01cb22b48635b0d2a0b8372cdb4a8136", size = 4960228, upload-time = "2025-09-16T21:06:38.182Z" }, + { url = "https://files.pythonhosted.org/packages/af/e0/ab62ee938b8d17bd1025cff569803cfc1c62dfdf89ffc78df6e092bff35f/cryptography-46.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:35aa1a44bd3e0efc3ef09cf924b3a0e2a57eda84074556f4506af2d294076685", size = 4577257, upload-time = "2025-09-16T21:06:39.998Z" }, + { url = "https://files.pythonhosted.org/packages/49/67/09a581c21da7189676678edd2bd37b64888c88c2d2727f2c3e0350194fba/cryptography-46.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:c457ad3f151d5fb380be99425b286167b358f76d97ad18b188b68097193ed95a", size = 4299023, upload-time = "2025-09-16T21:06:42.182Z" }, + { url = "https://files.pythonhosted.org/packages/af/28/2cb6d3d0d2c8ce8be4f19f4d83956c845c760a9e6dfe5b476cebed4f4f00/cryptography-46.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:399ef4c9be67f3902e5ca1d80e64b04498f8b56c19e1bc8d0825050ea5290410", size = 4925802, upload-time = "2025-09-16T21:06:44.31Z" }, + { url = "https://files.pythonhosted.org/packages/88/0b/1f31b6658c1dfa04e82b88de2d160e0e849ffb94353b1526dfb3a225a100/cryptography-46.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:378eff89b040cbce6169528f130ee75dceeb97eef396a801daec03b696434f06", size = 4577107, upload-time = "2025-09-16T21:06:46.324Z" }, + { url = "https://files.pythonhosted.org/packages/c2/af/507de3a1d4ded3068ddef188475d241bfc66563d99161585c8f2809fee01/cryptography-46.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c3648d6a5878fd1c9a22b1d43fa75efc069d5f54de12df95c638ae7ba88701d0", size = 4422506, upload-time = "2025-09-16T21:06:47.963Z" }, + { url = "https://files.pythonhosted.org/packages/47/aa/08e514756504d92334cabfe7fe792d10d977f2294ef126b2056b436450eb/cryptography-46.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fc30be952dd4334801d345d134c9ef0e9ccbaa8c3e1bc18925cbc4247b3e29c", size = 4684081, upload-time = "2025-09-16T21:06:49.667Z" }, + { url = "https://files.pythonhosted.org/packages/d0/ef/ffde6e334fbd4ace04a6d9ced4c5fe1ca9e6ded4ee21b077a6889b452a89/cryptography-46.0.0-cp314-cp314t-win32.whl", hash = "sha256:b8e7db4ce0b7297e88f3d02e6ee9a39382e0efaf1e8974ad353120a2b5a57ef7", size = 3029735, upload-time = "2025-09-16T21:06:51.301Z" }, + { url = "https://files.pythonhosted.org/packages/4a/78/a41aee8bc5659390806196b0ed4d388211d3b38172827e610a82a7cd7546/cryptography-46.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:40ee4ce3c34acaa5bc347615ec452c74ae8ff7db973a98c97c62293120f668c6", size = 3502172, upload-time = "2025-09-16T21:06:53.328Z" }, + { url = "https://files.pythonhosted.org/packages/f0/2b/7e7427c258fdeae867d236cc9cad0c5c56735bc4d2f4adf035933ab4c15f/cryptography-46.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:07a1be54f995ce14740bf8bbe1cc35f7a37760f992f73cf9f98a2a60b9b97419", size = 2912344, upload-time = "2025-09-16T21:06:56.808Z" }, + { url = "https://files.pythonhosted.org/packages/53/06/80e7256a4677c2e9eb762638e8200a51f6dd56d2e3de3e34d0a83c2f5f80/cryptography-46.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:1d2073313324226fd846e6b5fc340ed02d43fd7478f584741bd6b791c33c9fee", size = 7257206, upload-time = "2025-09-16T21:06:59.295Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b8/a5ed987f5c11b242713076121dddfff999d81fb492149c006a579d0e4099/cryptography-46.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83af84ebe7b6e9b6de05050c79f8cc0173c864ce747b53abce6a11e940efdc0d", size = 4301182, upload-time = "2025-09-16T21:07:01.624Z" }, + { url = "https://files.pythonhosted.org/packages/da/94/f1c1f30110c05fa5247bf460b17acfd52fa3f5c77e94ba19cff8957dc5e6/cryptography-46.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c3cd09b1490c1509bf3892bde9cef729795fae4a2fee0621f19be3321beca7e4", size = 4562561, upload-time = "2025-09-16T21:07:03.386Z" }, + { url = "https://files.pythonhosted.org/packages/5d/54/8decbf2f707350bedcd525833d3a0cc0203d8b080d926ad75d5c4de701ba/cryptography-46.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d14eaf1569d6252280516bedaffdd65267428cdbc3a8c2d6de63753cf0863d5e", size = 4301974, upload-time = "2025-09-16T21:07:04.962Z" }, + { url = "https://files.pythonhosted.org/packages/82/63/c34a2f3516c6b05801f129616a5a1c68a8c403b91f23f9db783ee1d4f700/cryptography-46.0.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ab3a14cecc741c8c03ad0ad46dfbf18de25218551931a23bca2731d46c706d83", size = 4009462, upload-time = "2025-09-16T21:07:06.569Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c5/92ef920a4cf8ff35fcf9da5a09f008a6977dcb9801c709799ec1bf2873fb/cryptography-46.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:8e8b222eb54e3e7d3743a7c2b1f7fa7df7a9add790307bb34327c88ec85fe087", size = 4980769, upload-time = "2025-09-16T21:07:08.269Z" }, + { url = "https://files.pythonhosted.org/packages/a9/8f/1705f7ea3b9468c4a4fef6cce631db14feb6748499870a4772993cbeb729/cryptography-46.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7f3f88df0c9b248dcc2e76124f9140621aca187ccc396b87bc363f890acf3a30", size = 4591812, upload-time = "2025-09-16T21:07:10.288Z" }, + { url = "https://files.pythonhosted.org/packages/34/b9/2d797ce9d346b8bac9f570b43e6e14226ff0f625f7f6f2f95d9065e316e3/cryptography-46.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9aa85222f03fdb30defabc7a9e1e3d4ec76eb74ea9fe1504b2800844f9c98440", size = 4301844, upload-time = "2025-09-16T21:07:12.522Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2d/8efc9712997b46aea2ac8f74adc31f780ac4662e3b107ecad0d5c1a0c7f8/cryptography-46.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:f9aaf2a91302e1490c068d2f3af7df4137ac2b36600f5bd26e53d9ec320412d3", size = 4943257, upload-time = "2025-09-16T21:07:14.289Z" }, + { url = "https://files.pythonhosted.org/packages/c4/0c/bc365287a97d28aa7feef8810884831b2a38a8dc4cf0f8d6927ad1568d27/cryptography-46.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:32670ca085150ff36b438c17f2dfc54146fe4a074ebf0a76d72fb1b419a974bc", size = 4591154, upload-time = "2025-09-16T21:07:16.271Z" }, + { url = "https://files.pythonhosted.org/packages/51/3b/0b15107277b0c558c02027da615f4e78c892f22c6a04d29c6ad43fcddca6/cryptography-46.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0f58183453032727a65e6605240e7a3824fd1d6a7e75d2b537e280286ab79a52", size = 4428200, upload-time = "2025-09-16T21:07:18.118Z" }, + { url = "https://files.pythonhosted.org/packages/cf/24/814d69418247ea2cfc985eec6678239013500d745bc7a0a35a32c2e2f3be/cryptography-46.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4bc257c2d5d865ed37d0bd7c500baa71f939a7952c424f28632298d80ccd5ec1", size = 4699862, upload-time = "2025-09-16T21:07:20.219Z" }, + { url = "https://files.pythonhosted.org/packages/fb/1e/665c718e0c45281a4e22454fa8a9bd8835f1ceb667b9ffe807baa41cd681/cryptography-46.0.0-cp38-abi3-win32.whl", hash = "sha256:df932ac70388be034b2e046e34d636245d5eeb8140db24a6b4c2268cd2073270", size = 3043766, upload-time = "2025-09-16T21:07:21.969Z" }, + { url = "https://files.pythonhosted.org/packages/78/7e/12e1e13abff381c702697845d1cf372939957735f49ef66f2061f38da32f/cryptography-46.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:274f8b2eb3616709f437326185eb563eb4e5813d01ebe2029b61bfe7d9995fbb", size = 3517216, upload-time = "2025-09-16T21:07:24.024Z" }, + { url = "https://files.pythonhosted.org/packages/ad/55/009497b2ae7375db090b41f9fe7a1a7362f804ddfe17ed9e34f748fcb0e5/cryptography-46.0.0-cp38-abi3-win_arm64.whl", hash = "sha256:249c41f2bbfa026615e7bdca47e4a66135baa81b08509ab240a2e666f6af5966", size = 2923145, upload-time = "2025-09-16T21:07:25.74Z" }, +] + +[[package]] +name = "cytoolz" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "toolz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/f9/3243eed3a6545c2a33a21f74f655e3fcb5d2192613cd3db81a93369eb339/cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6", size = 626652, upload-time = "2024-12-13T05:47:36.672Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/e8/218098344ed2cb5f8441fade9b2428e435e7073962374a9c71e59ac141a7/cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4", size = 414121, upload-time = "2024-12-13T05:45:26.588Z" }, + { url = "https://files.pythonhosted.org/packages/de/27/4d729a5653718109262b758fec1a959aa9facb74c15460d9074dc76d6635/cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662", size = 390904, upload-time = "2024-12-13T05:45:27.718Z" }, + { url = "https://files.pythonhosted.org/packages/72/c0/cbabfa788bab9c6038953bf9478adaec06e88903a726946ea7c88092f5c4/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3", size = 2090734, upload-time = "2024-12-13T05:45:30.515Z" }, + { url = "https://files.pythonhosted.org/packages/c3/66/369262c60f9423c2da82a60864a259c852f1aa122aced4acd2c679af58c0/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1", size = 2155933, upload-time = "2024-12-13T05:45:32.721Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/ee55186802f8d24b5fbf9a11405ccd1203b30eded07cc17750618219b94e/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8", size = 2171903, upload-time = "2024-12-13T05:45:34.205Z" }, + { url = "https://files.pythonhosted.org/packages/a1/96/bd1a9f3396e9b7f618db8cd08d15630769ce3c8b7d0534f92cd639c977ae/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d", size = 2125270, upload-time = "2024-12-13T05:45:36.982Z" }, + { url = "https://files.pythonhosted.org/packages/28/48/2a3762873091c88a69e161111cfbc6c222ff145d57ff011a642b169f04f1/cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f", size = 1973967, upload-time = "2024-12-13T05:45:39.505Z" }, + { url = "https://files.pythonhosted.org/packages/e4/50/500bd69774bdc49a4d78ec8779eb6ac7c1a9d706bfd91cf2a1dba604373a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7", size = 2021695, upload-time = "2024-12-13T05:45:40.911Z" }, + { url = "https://files.pythonhosted.org/packages/e4/4e/ba5a0ce34869495eb50653de8d676847490cf13a2cac1760fc4d313e78de/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126", size = 2010177, upload-time = "2024-12-13T05:45:42.48Z" }, + { url = "https://files.pythonhosted.org/packages/87/57/615c630b3089a13adb15351d958d227430cf624f03b1dd39eb52c34c1f59/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0", size = 2154321, upload-time = "2024-12-13T05:45:43.979Z" }, + { url = "https://files.pythonhosted.org/packages/7f/0f/fe1aa2d931e3b35ecc05215bd75da945ea7346095b3b6f6027164e602d5a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b", size = 2188374, upload-time = "2024-12-13T05:45:46.783Z" }, + { url = "https://files.pythonhosted.org/packages/de/fa/fd363d97a641b6d0e2fd1d5c35b8fd41d9ccaeb4df56302f53bf23a58e3a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d", size = 2077911, upload-time = "2024-12-13T05:45:48.219Z" }, + { url = "https://files.pythonhosted.org/packages/d9/68/0a22946b98ae5201b54ccb4e651295285c0fb79406022b6ee8b2f791940c/cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9", size = 321903, upload-time = "2024-12-13T05:45:50.3Z" }, + { url = "https://files.pythonhosted.org/packages/62/1a/f3903197956055032f8cb297342e2dff07e50f83991aebfe5b4c4fcb55e4/cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b", size = 364490, upload-time = "2024-12-13T05:45:51.494Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2e/a9f069db0107749e9e72baf6c21abe3f006841a3bcfdc9b8420e22ef31eb/cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0", size = 407365, upload-time = "2024-12-13T05:45:52.803Z" }, + { url = "https://files.pythonhosted.org/packages/a9/9b/5e87dd0e31f54c778b4f9f34cc14c1162d3096c8d746b0f8be97d70dd73c/cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a", size = 385233, upload-time = "2024-12-13T05:45:53.994Z" }, + { url = "https://files.pythonhosted.org/packages/63/00/2fd32b16284cdb97cfe092822179bc0c3bcdd5e927dd39f986169a517642/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242", size = 2062903, upload-time = "2024-12-13T05:45:55.202Z" }, + { url = "https://files.pythonhosted.org/packages/85/39/b3cbb5a9847ba59584a263772ad4f8ca2dbfd2a0e11efd09211d1219804c/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296", size = 2139517, upload-time = "2024-12-13T05:45:56.804Z" }, + { url = "https://files.pythonhosted.org/packages/ea/39/bfcab4a46d50c467e36fe704f19d8904efead417787806ee210327f68390/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b", size = 2154849, upload-time = "2024-12-13T05:45:58.814Z" }, + { url = "https://files.pythonhosted.org/packages/fd/42/3bc6ee61b0aa47e1cb40819adc1a456d7efa809f0dea9faddacb43fdde8f/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b", size = 2102302, upload-time = "2024-12-13T05:46:00.181Z" }, + { url = "https://files.pythonhosted.org/packages/00/66/3f636c6ddea7b18026b90a8c238af472e423b86e427b11df02213689b012/cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266", size = 1960872, upload-time = "2024-12-13T05:46:01.612Z" }, + { url = "https://files.pythonhosted.org/packages/40/36/cb3b7cdd651007b69f9c48e9d104cec7cb8dc53afa1d6a720e5ad08022fa/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5", size = 2014430, upload-time = "2024-12-13T05:46:03.022Z" }, + { url = "https://files.pythonhosted.org/packages/88/3f/2e9bd2a16cfd269808922147551dcb2d8b68ba54a2c4deca2fa6a6cd0d5f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3", size = 2003127, upload-time = "2024-12-13T05:46:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/c4/7d/08604ff940aa784df8343c387fdf2489b948b714a6afb587775ae94da912/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296", size = 2142369, upload-time = "2024-12-13T05:46:06.004Z" }, + { url = "https://files.pythonhosted.org/packages/d2/c6/39919a0645bdbdf720e97cae107f959ea9d1267fbc3b0d94fc6e1d12ac8f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140", size = 2180427, upload-time = "2024-12-13T05:46:07.526Z" }, + { url = "https://files.pythonhosted.org/packages/d8/03/dbb9d47556ee54337e7e0ac209d17ceff2d2a197c34de08005abc7a7449b/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581", size = 2069785, upload-time = "2024-12-13T05:46:10.122Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f8/11bb7b8947002231faae3ec2342df5896afbc19eb783a332cce6d219ff79/cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9", size = 320685, upload-time = "2024-12-13T05:46:11.553Z" }, + { url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297", size = 362898, upload-time = "2024-12-13T05:46:12.771Z" }, +] + +[[package]] +name = "datamodel-code-generator" +version = "0.35.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "black" }, + { name = "genson" }, + { name = "inflect" }, + { name = "isort" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/e1/dbf7c2edb1b1db1f4fd472ee92f985ec97d58902512013d9c4584108329c/datamodel_code_generator-0.35.0.tar.gz", hash = "sha256:46805fa2515d3871f6bfafce9aa63128e735a7a6a4cfcbf9c27b3794ee4ea846", size = 459915, upload-time = "2025-10-09T19:26:49.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/ef/0ed17459fe6076219fcd45f69a0bb4bd1cb041b39095ca2946808a9b5f04/datamodel_code_generator-0.35.0-py3-none-any.whl", hash = "sha256:c356d1e4a555f86667a4262db03d4598a30caeda8f51786555fd269c8abb806b", size = 121436, upload-time = "2025-10-09T19:26:48.437Z" }, +] + +[[package]] +name = "deltalake" +version = "1.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "arro3-core" }, + { name = "deprecated" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3b/04/b905b40ac511155944c25bd0c541a9b82d456ee35e7859be25e788ae8bff/deltalake-1.1.4.tar.gz", hash = "sha256:2e978950d420e050bbdcb5f62e3be93d331cb516ab4c9b1694cf1a7887c63e25", size = 5097828, upload-time = "2025-08-08T10:13:35.504Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/e8/aaf28573d6c29faccd69a55763aab77c33ef383122e5e57b90f4bb1b65d5/deltalake-1.1.4-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2fb21d2405928db57c56f9b459b5d0cec9cdbbcb882bfea1de1e98d9dc6c9f3d", size = 43310898, upload-time = "2025-08-08T10:10:09.855Z" }, + { url = "https://files.pythonhosted.org/packages/71/3e/d1fc3685a3414e61a764a0698df5342f67f28b102387cc4482cfc5544518/deltalake-1.1.4-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8ad7d2a19b5e76aad43ea359305c892b014bc07f85e71beb95b6e9c672d116ee", size = 39906549, upload-time = "2025-08-08T10:18:36.631Z" }, + { url = "https://files.pythonhosted.org/packages/d6/94/18f5cf3d50a1aca6759f1e61ad23608bbd1aa3bfe2fc247858c5a1367cc6/deltalake-1.1.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af269b95fc858134a051fd08da294e8a3d64301f61f99ed0c54269fc6c177c6e", size = 41789854, upload-time = "2025-08-08T10:14:32.351Z" }, + { url = "https://files.pythonhosted.org/packages/24/00/24dbce2a5c13c69b04dba718e64e4f74d5882ac94350228a004a27e5975c/deltalake-1.1.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f28480d3a19f93a75687a1a2a4449b3a6b7355243b765e4379f501dcac03eea", size = 53068945, upload-time = "2025-08-08T10:13:32.735Z" }, + { url = "https://files.pythonhosted.org/packages/92/e3/6a2a8ea39e16441825f7348a1d130653415c85a59355ee064dc5f0932f22/deltalake-1.1.4-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:17986efcf450ba54245d8cb41a947434ebb1a866e8746129075d49c504300cd9", size = 41800723, upload-time = "2025-08-08T10:15:16.568Z" }, + { url = "https://files.pythonhosted.org/packages/65/95/6e7a30c3d97593539411c3afb2331f0ed9e4c8115bea540ddd23a6b9155e/deltalake-1.1.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fe441bf4e81df7ff8d9069677cd9e8e9e2e7020ec80bed2f7feefba617f3c2f9", size = 45420869, upload-time = "2025-08-08T10:14:18.531Z" }, + { url = "https://files.pythonhosted.org/packages/b8/9f/3e8218adab1e8681c9de1835a8a08592214e5e0da4d1e220f59c20112b00/deltalake-1.1.4-cp39-abi3-win_amd64.whl", hash = "sha256:62ad8443cda6ec7b826c1bfe7e935d02df86670d8c7c1d9909744f07cb20a887", size = 43867754, upload-time = "2025-08-08T10:27:08.862Z" }, +] + +[[package]] +name = "deprecated" +version = "1.2.18" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/97/06afe62762c9a8a86af0cfb7bfdab22a43ad17138b07af5b1a58442690a2/deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d", size = 2928744, upload-time = "2025-01-27T10:46:25.7Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/c6/ac0b6c1e2d138f1002bcf799d330bd6d85084fece321e662a14223794041/Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec", size = 9998, upload-time = "2025-01-27T10:46:09.186Z" }, +] + +[[package]] +name = "docker" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "requests" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/9b/4a2ea29aeba62471211598dac5d96825bb49348fa07e906ea930394a83ce/docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", size = 117834, upload-time = "2024-05-23T11:13:57.216Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/26/57c6fb270950d476074c087527a558ccb6f4436657314bfb6cdf484114c4/docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0", size = 147774, upload-time = "2024-05-23T11:13:55.01Z" }, +] + +[[package]] +name = "docutils" +version = "0.22.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/c0/89fe6215b443b919cb98a5002e107cb5026854ed1ccb6b5833e0768419d1/docutils-0.22.2.tar.gz", hash = "sha256:9fdb771707c8784c8f2728b67cb2c691305933d68137ef95a75db5f4dfbc213d", size = 2289092, upload-time = "2025-09-20T17:55:47.994Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/dd/f95350e853a4468ec37478414fc04ae2d61dad7a947b3015c3dcc51a09b9/docutils-0.22.2-py3-none-any.whl", hash = "sha256:b0e98d679283fc3bb0ead8a5da7f501baa632654e7056e9c5846842213d674d8", size = 632667, upload-time = "2025-09-20T17:55:43.052Z" }, +] + +[[package]] +name = "eth-hash" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227, upload-time = "2025-01-13T21:29:21.765Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028, upload-time = "2025-01-13T21:29:19.365Z" }, +] + +[package.optional-dependencies] +pysha3 = [ + { name = "safe-pysha3" }, +] + +[[package]] +name = "eth-typing" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/54/62aa24b9cc708f06316167ee71c362779c8ed21fc8234a5cd94a8f53b623/eth_typing-5.2.1.tar.gz", hash = "sha256:7557300dbf02a93c70fa44af352b5c4a58f94e997a0fd6797fb7d1c29d9538ee", size = 21806, upload-time = "2025-04-14T20:39:28.217Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/72/c370bbe4c53da7bf998d3523f5a0f38867654923a82192df88d0705013d3/eth_typing-5.2.1-py3-none-any.whl", hash = "sha256:b0c2812ff978267563b80e9d701f487dd926f1d376d674f3b535cfe28b665d3d", size = 19163, upload-time = "2025-04-14T20:39:26.571Z" }, +] + +[[package]] +name = "eth-utils" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cytoolz", marker = "implementation_name == 'cpython'" }, + { name = "eth-hash" }, + { name = "eth-typing" }, + { name = "pydantic" }, + { name = "toolz", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e6/e1/ee3a8728227c3558853e63ff35bd4c449abdf5022a19601369400deacd39/eth_utils-5.3.1.tar.gz", hash = "sha256:c94e2d2abd024a9a42023b4ddc1c645814ff3d6a737b33d5cfd890ebf159c2d1", size = 123506, upload-time = "2025-08-27T16:37:17.378Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/4d/257cdc01ada430b8e84b9f2385c2553f33218f5b47da9adf0a616308d4b7/eth_utils-5.3.1-py3-none-any.whl", hash = "sha256:1f5476d8f29588d25b8ae4987e1ffdfae6d4c09026e476c4aad13b32dda3ead0", size = 102529, upload-time = "2025-08-27T16:37:15.449Z" }, +] + +[[package]] +name = "execnet" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size = 166524, upload-time = "2024-04-08T09:04:19.245Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612, upload-time = "2024-04-08T09:04:17.414Z" }, +] + +[[package]] +name = "filelock" +version = "3.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, +] + +[[package]] +name = "fsspec" +version = "2025.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/e0/bab50af11c2d75c9c4a2a26a5254573c0bd97cea152254401510950486fa/fsspec-2025.9.0.tar.gz", hash = "sha256:19fd429483d25d28b65ec68f9f4adc16c17ea2c7c7bf54ec61360d478fb19c19", size = 304847, upload-time = "2025-09-02T19:10:49.215Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/71/70db47e4f6ce3e5c37a607355f80da8860a33226be640226ac52cb05ef2e/fsspec-2025.9.0-py3-none-any.whl", hash = "sha256:530dc2a2af60a414a832059574df4a6e10cce927f6f4a78209390fe38955cfb7", size = 199289, upload-time = "2025-09-02T19:10:47.708Z" }, +] + +[[package]] +name = "genson" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/cf/2303c8ad276dcf5ee2ad6cf69c4338fd86ef0f471a5207b069adf7a393cf/genson-1.3.0.tar.gz", hash = "sha256:e02db9ac2e3fd29e65b5286f7135762e2cd8a986537c075b06fc5f1517308e37", size = 34919, upload-time = "2024-05-15T22:08:49.123Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/5c/e226de133afd8bb267ec27eead9ae3d784b95b39a287ed404caab39a5f50/genson-1.3.0-py3-none-any.whl", hash = "sha256:468feccd00274cc7e4c09e84b08704270ba8d95232aa280f65b986139cec67f7", size = 21470, upload-time = "2024-05-15T22:08:47.056Z" }, +] + +[[package]] +name = "google-api-core" +version = "2.25.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/cd/63f1557235c2440fe0577acdbc32577c5c002684c58c7f4d770a92366a24/google_api_core-2.25.2.tar.gz", hash = "sha256:1c63aa6af0d0d5e37966f157a77f9396d820fba59f9e43e9415bc3dc5baff300", size = 166266, upload-time = "2025-10-03T00:07:34.778Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/d8/894716a5423933f5c8d2d5f04b16f052a515f78e815dab0c2c6f1fd105dc/google_api_core-2.25.2-py3-none-any.whl", hash = "sha256:e9a8f62d363dc8424a8497f4c2a47d6bcda6c16514c935629c257ab5d10210e7", size = 162489, upload-time = "2025-10-03T00:07:32.924Z" }, +] + +[package.optional-dependencies] +grpc = [ + { name = "grpcio" }, + { name = "grpcio-status" }, +] + +[[package]] +name = "google-auth" +version = "2.41.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "pyasn1-modules" }, + { name = "rsa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/af/5129ce5b2f9688d2fa49b463e544972a7c82b0fdb50980dafee92e121d9f/google_auth-2.41.1.tar.gz", hash = "sha256:b76b7b1f9e61f0cb7e88870d14f6a94aeef248959ef6992670efee37709cbfd2", size = 292284, upload-time = "2025-09-30T22:51:26.363Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/a4/7319a2a8add4cc352be9e3efeff5e2aacee917c85ca2fa1647e29089983c/google_auth-2.41.1-py2.py3-none-any.whl", hash = "sha256:754843be95575b9a19c604a848a41be03f7f2afd8c019f716dc1f51ee41c639d", size = 221302, upload-time = "2025-09-30T22:51:24.212Z" }, +] + +[[package]] +name = "google-cloud-bigquery" +version = "3.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-resumable-media" }, + { name = "packaging" }, + { name = "python-dateutil" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/b2/a17e40afcf9487e3d17db5e36728ffe75c8d5671c46f419d7b6528a5728a/google_cloud_bigquery-3.38.0.tar.gz", hash = "sha256:8afcb7116f5eac849097a344eb8bfda78b7cfaae128e60e019193dd483873520", size = 503666, upload-time = "2025-09-17T20:33:33.47Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/3c/c8cada9ec282b29232ed9aed5a0b5cca6cf5367cb2ffa8ad0d2583d743f1/google_cloud_bigquery-3.38.0-py3-none-any.whl", hash = "sha256:e06e93ff7b245b239945ef59cb59616057598d369edac457ebf292bd61984da6", size = 259257, upload-time = "2025-09-17T20:33:31.404Z" }, +] + +[[package]] +name = "google-cloud-core" +version = "2.4.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/b8/2b53838d2acd6ec6168fd284a990c76695e84c65deee79c9f3a4276f6b4f/google_cloud_core-2.4.3.tar.gz", hash = "sha256:1fab62d7102844b278fe6dead3af32408b1df3eb06f5c7e8634cbd40edc4da53", size = 35861, upload-time = "2025-03-10T21:05:38.948Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/86/bda7241a8da2d28a754aad2ba0f6776e35b67e37c36ae0c45d49370f1014/google_cloud_core-2.4.3-py2.py3-none-any.whl", hash = "sha256:5130f9f4c14b4fafdff75c79448f9495cfade0d8775facf1b09c3bf67e027f6e", size = 29348, upload-time = "2025-03-10T21:05:37.785Z" }, +] + +[[package]] +name = "google-cloud-storage" +version = "3.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-crc32c" }, + { name = "google-resumable-media" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/ef/7cefdca67a6c8b3af0ec38612f9e78e5a9f6179dd91352772ae1a9849246/google_cloud_storage-3.4.1.tar.gz", hash = "sha256:6f041a297e23a4b485fad8c305a7a6e6831855c208bcbe74d00332a909f82268", size = 17238203, upload-time = "2025-10-08T18:43:39.665Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/6e/b47d83d3a35231c6232566341b0355cce78fd4e6988a7343725408547b2c/google_cloud_storage-3.4.1-py3-none-any.whl", hash = "sha256:972764cc0392aa097be8f49a5354e22eb47c3f62370067fb1571ffff4a1c1189", size = 290142, upload-time = "2025-10-08T18:43:37.524Z" }, +] + +[[package]] +name = "google-crc32c" +version = "1.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/ae/87802e6d9f9d69adfaedfcfd599266bf386a54d0be058b532d04c794f76d/google_crc32c-1.7.1.tar.gz", hash = "sha256:2bff2305f98846f3e825dbeec9ee406f89da7962accdb29356e4eadc251bd472", size = 14495, upload-time = "2025-03-26T14:29:13.32Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dd/b7/787e2453cf8639c94b3d06c9d61f512234a82e1d12d13d18584bd3049904/google_crc32c-1.7.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2d73a68a653c57281401871dd4aeebbb6af3191dcac751a76ce430df4d403194", size = 30470, upload-time = "2025-03-26T14:34:31.655Z" }, + { url = "https://files.pythonhosted.org/packages/ed/b4/6042c2b0cbac3ec3a69bb4c49b28d2f517b7a0f4a0232603c42c58e22b44/google_crc32c-1.7.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:22beacf83baaf59f9d3ab2bbb4db0fb018da8e5aebdce07ef9f09fce8220285e", size = 30315, upload-time = "2025-03-26T15:01:54.634Z" }, + { url = "https://files.pythonhosted.org/packages/29/ad/01e7a61a5d059bc57b702d9ff6a18b2585ad97f720bd0a0dbe215df1ab0e/google_crc32c-1.7.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19eafa0e4af11b0a4eb3974483d55d2d77ad1911e6cf6f832e1574f6781fd337", size = 33180, upload-time = "2025-03-26T14:41:32.168Z" }, + { url = "https://files.pythonhosted.org/packages/3b/a5/7279055cf004561894ed3a7bfdf5bf90a53f28fadd01af7cd166e88ddf16/google_crc32c-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6d86616faaea68101195c6bdc40c494e4d76f41e07a37ffdef270879c15fb65", size = 32794, upload-time = "2025-03-26T14:41:33.264Z" }, + { url = "https://files.pythonhosted.org/packages/0f/d6/77060dbd140c624e42ae3ece3df53b9d811000729a5c821b9fd671ceaac6/google_crc32c-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:b7491bdc0c7564fcf48c0179d2048ab2f7c7ba36b84ccd3a3e1c3f7a72d3bba6", size = 33477, upload-time = "2025-03-26T14:29:10.94Z" }, + { url = "https://files.pythonhosted.org/packages/8b/72/b8d785e9184ba6297a8620c8a37cf6e39b81a8ca01bb0796d7cbb28b3386/google_crc32c-1.7.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:df8b38bdaf1629d62d51be8bdd04888f37c451564c2042d36e5812da9eff3c35", size = 30467, upload-time = "2025-03-26T14:36:06.909Z" }, + { url = "https://files.pythonhosted.org/packages/34/25/5f18076968212067c4e8ea95bf3b69669f9fc698476e5f5eb97d5b37999f/google_crc32c-1.7.1-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:e42e20a83a29aa2709a0cf271c7f8aefaa23b7ab52e53b322585297bb94d4638", size = 30309, upload-time = "2025-03-26T15:06:15.318Z" }, + { url = "https://files.pythonhosted.org/packages/92/83/9228fe65bf70e93e419f38bdf6c5ca5083fc6d32886ee79b450ceefd1dbd/google_crc32c-1.7.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:905a385140bf492ac300026717af339790921f411c0dfd9aa5a9e69a08ed32eb", size = 33133, upload-time = "2025-03-26T14:41:34.388Z" }, + { url = "https://files.pythonhosted.org/packages/c3/ca/1ea2fd13ff9f8955b85e7956872fdb7050c4ace8a2306a6d177edb9cf7fe/google_crc32c-1.7.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b211ddaf20f7ebeec5c333448582c224a7c90a9d98826fbab82c0ddc11348e6", size = 32773, upload-time = "2025-03-26T14:41:35.19Z" }, + { url = "https://files.pythonhosted.org/packages/89/32/a22a281806e3ef21b72db16f948cad22ec68e4bdd384139291e00ff82fe2/google_crc32c-1.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:0f99eaa09a9a7e642a61e06742856eec8b19fc0037832e03f941fe7cf0c8e4db", size = 33475, upload-time = "2025-03-26T14:29:11.771Z" }, + { url = "https://files.pythonhosted.org/packages/b8/c5/002975aff514e57fc084ba155697a049b3f9b52225ec3bc0f542871dd524/google_crc32c-1.7.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32d1da0d74ec5634a05f53ef7df18fc646666a25efaaca9fc7dcfd4caf1d98c3", size = 33243, upload-time = "2025-03-26T14:41:35.975Z" }, + { url = "https://files.pythonhosted.org/packages/61/cb/c585282a03a0cea70fcaa1bf55d5d702d0f2351094d663ec3be1c6c67c52/google_crc32c-1.7.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e10554d4abc5238823112c2ad7e4560f96c7bf3820b202660373d769d9e6e4c9", size = 32870, upload-time = "2025-03-26T14:41:37.08Z" }, +] + +[[package]] +name = "google-resumable-media" +version = "2.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-crc32c" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/5a/0efdc02665dca14e0837b62c8a1a93132c264bd02054a15abb2218afe0ae/google_resumable_media-2.7.2.tar.gz", hash = "sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0", size = 2163099, upload-time = "2024-08-07T22:20:38.555Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/35/b8d3baf8c46695858cb9d8835a53baa1eeb9906ddaf2f728a5f5b640fd1e/google_resumable_media-2.7.2-py2.py3-none-any.whl", hash = "sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa", size = 81251, upload-time = "2024-08-07T22:20:36.409Z" }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.70.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/24/33db22342cf4a2ea27c9955e6713140fedd51e8b141b5ce5260897020f1a/googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257", size = 145903, upload-time = "2025-04-14T10:17:02.924Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530, upload-time = "2025-04-14T10:17:01.271Z" }, +] + +[[package]] +name = "greenlet" +version = "3.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/69/9b804adb5fd0671f367781560eb5eb586c4d495277c93bde4307b9e28068/greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", size = 274079, upload-time = "2025-08-07T13:15:45.033Z" }, + { url = "https://files.pythonhosted.org/packages/46/e9/d2a80c99f19a153eff70bc451ab78615583b8dac0754cfb942223d2c1a0d/greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", size = 640997, upload-time = "2025-08-07T13:42:56.234Z" }, + { url = "https://files.pythonhosted.org/packages/3b/16/035dcfcc48715ccd345f3a93183267167cdd162ad123cd93067d86f27ce4/greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968", size = 655185, upload-time = "2025-08-07T13:45:27.624Z" }, + { url = "https://files.pythonhosted.org/packages/31/da/0386695eef69ffae1ad726881571dfe28b41970173947e7c558d9998de0f/greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9", size = 649926, upload-time = "2025-08-07T13:53:15.251Z" }, + { url = "https://files.pythonhosted.org/packages/68/88/69bf19fd4dc19981928ceacbc5fd4bb6bc2215d53199e367832e98d1d8fe/greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6", size = 651839, upload-time = "2025-08-07T13:18:30.281Z" }, + { url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586, upload-time = "2025-08-07T13:18:28.544Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281, upload-time = "2025-08-07T13:42:39.858Z" }, + { url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142, upload-time = "2025-08-07T13:18:22.981Z" }, + { url = "https://files.pythonhosted.org/packages/27/45/80935968b53cfd3f33cf99ea5f08227f2646e044568c9b1555b58ffd61c2/greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0", size = 1564846, upload-time = "2025-11-04T12:42:15.191Z" }, + { url = "https://files.pythonhosted.org/packages/69/02/b7c30e5e04752cb4db6202a3858b149c0710e5453b71a3b2aec5d78a1aab/greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d", size = 1633814, upload-time = "2025-11-04T12:42:17.175Z" }, + { url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899, upload-time = "2025-08-07T13:38:53.448Z" }, + { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" }, + { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" }, + { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" }, + { url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516, upload-time = "2025-08-07T13:53:16.314Z" }, + { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" }, + { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" }, + { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" }, + { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" }, + { url = "https://files.pythonhosted.org/packages/1c/53/f9c440463b3057485b8594d7a638bed53ba531165ef0ca0e6c364b5cc807/greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b", size = 1564759, upload-time = "2025-11-04T12:42:19.395Z" }, + { url = "https://files.pythonhosted.org/packages/47/e4/3bb4240abdd0a8d23f4f88adec746a3099f0d86bfedb623f063b2e3b4df0/greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929", size = 1634288, upload-time = "2025-11-04T12:42:21.174Z" }, + { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" }, + { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" }, + { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" }, + { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" }, + { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" }, + { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/23/6e/74407aed965a4ab6ddd93a7ded3180b730d281c77b765788419484cdfeef/greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269", size = 1612508, upload-time = "2025-11-04T12:42:23.427Z" }, + { url = "https://files.pythonhosted.org/packages/0d/da/343cd760ab2f92bac1845ca07ee3faea9fe52bee65f7bcb19f16ad7de08b/greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681", size = 1680760, upload-time = "2025-11-04T12:42:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" }, +] + +[[package]] +name = "grpcio" +version = "1.75.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/f7/8963848164c7604efb3a3e6ee457fdb3a469653e19002bd24742473254f8/grpcio-1.75.1.tar.gz", hash = "sha256:3e81d89ece99b9ace23a6916880baca613c03a799925afb2857887efa8b1b3d2", size = 12731327, upload-time = "2025-09-26T09:03:36.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/81/42be79e73a50aaa20af66731c2defeb0e8c9008d9935a64dd8ea8e8c44eb/grpcio-1.75.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:7b888b33cd14085d86176b1628ad2fcbff94cfbbe7809465097aa0132e58b018", size = 5668314, upload-time = "2025-09-26T09:01:55.424Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a7/3686ed15822fedc58c22f82b3a7403d9faf38d7c33de46d4de6f06e49426/grpcio-1.75.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:8775036efe4ad2085975531d221535329f5dac99b6c2a854a995456098f99546", size = 11476125, upload-time = "2025-09-26T09:01:57.927Z" }, + { url = "https://files.pythonhosted.org/packages/14/85/21c71d674f03345ab183c634ecd889d3330177e27baea8d5d247a89b6442/grpcio-1.75.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb658f703468d7fbb5dcc4037c65391b7dc34f808ac46ed9136c24fc5eeb041d", size = 6246335, upload-time = "2025-09-26T09:02:00.76Z" }, + { url = "https://files.pythonhosted.org/packages/fd/db/3beb661bc56a385ae4fa6b0e70f6b91ac99d47afb726fe76aaff87ebb116/grpcio-1.75.1-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4b7177a1cdb3c51b02b0c0a256b0a72fdab719600a693e0e9037949efffb200b", size = 6916309, upload-time = "2025-09-26T09:02:02.894Z" }, + { url = "https://files.pythonhosted.org/packages/1e/9c/eda9fe57f2b84343d44c1b66cf3831c973ba29b078b16a27d4587a1fdd47/grpcio-1.75.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7d4fa6ccc3ec2e68a04f7b883d354d7fea22a34c44ce535a2f0c0049cf626ddf", size = 6435419, upload-time = "2025-09-26T09:02:05.055Z" }, + { url = "https://files.pythonhosted.org/packages/c3/b8/090c98983e0a9d602e3f919a6e2d4e470a8b489452905f9a0fa472cac059/grpcio-1.75.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3d86880ecaeb5b2f0a8afa63824de93adb8ebe4e49d0e51442532f4e08add7d6", size = 7064893, upload-time = "2025-09-26T09:02:07.275Z" }, + { url = "https://files.pythonhosted.org/packages/ec/c0/6d53d4dbbd00f8bd81571f5478d8a95528b716e0eddb4217cc7cb45aae5f/grpcio-1.75.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a8041d2f9e8a742aeae96f4b047ee44e73619f4f9d24565e84d5446c623673b6", size = 8011922, upload-time = "2025-09-26T09:02:09.527Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7c/48455b2d0c5949678d6982c3e31ea4d89df4e16131b03f7d5c590811cbe9/grpcio-1.75.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3652516048bf4c314ce12be37423c79829f46efffb390ad64149a10c6071e8de", size = 7466181, upload-time = "2025-09-26T09:02:12.279Z" }, + { url = "https://files.pythonhosted.org/packages/fd/12/04a0e79081e3170b6124f8cba9b6275871276be06c156ef981033f691880/grpcio-1.75.1-cp312-cp312-win32.whl", hash = "sha256:44b62345d8403975513af88da2f3d5cc76f73ca538ba46596f92a127c2aea945", size = 3938543, upload-time = "2025-09-26T09:02:14.77Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d7/11350d9d7fb5adc73d2b0ebf6ac1cc70135577701e607407fe6739a90021/grpcio-1.75.1-cp312-cp312-win_amd64.whl", hash = "sha256:b1e191c5c465fa777d4cafbaacf0c01e0d5278022082c0abbd2ee1d6454ed94d", size = 4641938, upload-time = "2025-09-26T09:02:16.927Z" }, + { url = "https://files.pythonhosted.org/packages/46/74/bac4ab9f7722164afdf263ae31ba97b8174c667153510322a5eba4194c32/grpcio-1.75.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:3bed22e750d91d53d9e31e0af35a7b0b51367e974e14a4ff229db5b207647884", size = 5672779, upload-time = "2025-09-26T09:02:19.11Z" }, + { url = "https://files.pythonhosted.org/packages/a6/52/d0483cfa667cddaa294e3ab88fd2c2a6e9dc1a1928c0e5911e2e54bd5b50/grpcio-1.75.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:5b8f381eadcd6ecaa143a21e9e80a26424c76a0a9b3d546febe6648f3a36a5ac", size = 11470623, upload-time = "2025-09-26T09:02:22.117Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e4/d1954dce2972e32384db6a30273275e8c8ea5a44b80347f9055589333b3f/grpcio-1.75.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5bf4001d3293e3414d0cf99ff9b1139106e57c3a66dfff0c5f60b2a6286ec133", size = 6248838, upload-time = "2025-09-26T09:02:26.426Z" }, + { url = "https://files.pythonhosted.org/packages/06/43/073363bf63826ba8077c335d797a8d026f129dc0912b69c42feaf8f0cd26/grpcio-1.75.1-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f82ff474103e26351dacfe8d50214e7c9322960d8d07ba7fa1d05ff981c8b2d", size = 6922663, upload-time = "2025-09-26T09:02:28.724Z" }, + { url = "https://files.pythonhosted.org/packages/c2/6f/076ac0df6c359117676cacfa8a377e2abcecec6a6599a15a672d331f6680/grpcio-1.75.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0ee119f4f88d9f75414217823d21d75bfe0e6ed40135b0cbbfc6376bc9f7757d", size = 6436149, upload-time = "2025-09-26T09:02:30.971Z" }, + { url = "https://files.pythonhosted.org/packages/6b/27/1d08824f1d573fcb1fa35ede40d6020e68a04391709939e1c6f4193b445f/grpcio-1.75.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:664eecc3abe6d916fa6cf8dd6b778e62fb264a70f3430a3180995bf2da935446", size = 7067989, upload-time = "2025-09-26T09:02:33.233Z" }, + { url = "https://files.pythonhosted.org/packages/c6/98/98594cf97b8713feb06a8cb04eeef60b4757e3e2fb91aa0d9161da769843/grpcio-1.75.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c32193fa08b2fbebf08fe08e84f8a0aad32d87c3ad42999c65e9449871b1c66e", size = 8010717, upload-time = "2025-09-26T09:02:36.011Z" }, + { url = "https://files.pythonhosted.org/packages/8c/7e/bb80b1bba03c12158f9254762cdf5cced4a9bc2e8ed51ed335915a5a06ef/grpcio-1.75.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5cebe13088b9254f6e615bcf1da9131d46cfa4e88039454aca9cb65f639bd3bc", size = 7463822, upload-time = "2025-09-26T09:02:38.26Z" }, + { url = "https://files.pythonhosted.org/packages/23/1c/1ea57fdc06927eb5640f6750c697f596f26183573069189eeaf6ef86ba2d/grpcio-1.75.1-cp313-cp313-win32.whl", hash = "sha256:4b4c678e7ed50f8ae8b8dbad15a865ee73ce12668b6aaf411bf3258b5bc3f970", size = 3938490, upload-time = "2025-09-26T09:02:40.268Z" }, + { url = "https://files.pythonhosted.org/packages/4b/24/fbb8ff1ccadfbf78ad2401c41aceaf02b0d782c084530d8871ddd69a2d49/grpcio-1.75.1-cp313-cp313-win_amd64.whl", hash = "sha256:5573f51e3f296a1bcf71e7a690c092845fb223072120f4bdb7a5b48e111def66", size = 4642538, upload-time = "2025-09-26T09:02:42.519Z" }, + { url = "https://files.pythonhosted.org/packages/f2/1b/9a0a5cecd24302b9fdbcd55d15ed6267e5f3d5b898ff9ac8cbe17ee76129/grpcio-1.75.1-cp314-cp314-linux_armv7l.whl", hash = "sha256:c05da79068dd96723793bffc8d0e64c45f316248417515f28d22204d9dae51c7", size = 5673319, upload-time = "2025-09-26T09:02:44.742Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ec/9d6959429a83fbf5df8549c591a8a52bb313976f6646b79852c4884e3225/grpcio-1.75.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06373a94fd16ec287116a825161dca179a0402d0c60674ceeec8c9fba344fe66", size = 11480347, upload-time = "2025-09-26T09:02:47.539Z" }, + { url = "https://files.pythonhosted.org/packages/09/7a/26da709e42c4565c3d7bf999a9569da96243ce34a8271a968dee810a7cf1/grpcio-1.75.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4484f4b7287bdaa7a5b3980f3c7224c3c622669405d20f69549f5fb956ad0421", size = 6254706, upload-time = "2025-09-26T09:02:50.4Z" }, + { url = "https://files.pythonhosted.org/packages/f1/08/dcb26a319d3725f199c97e671d904d84ee5680de57d74c566a991cfab632/grpcio-1.75.1-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:2720c239c1180eee69f7883c1d4c83fc1a495a2535b5fa322887c70bf02b16e8", size = 6922501, upload-time = "2025-09-26T09:02:52.711Z" }, + { url = "https://files.pythonhosted.org/packages/78/66/044d412c98408a5e23cb348845979a2d17a2e2b6c3c34c1ec91b920f49d0/grpcio-1.75.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:07a554fa31c668cf0e7a188678ceeca3cb8fead29bbe455352e712ec33ca701c", size = 6437492, upload-time = "2025-09-26T09:02:55.542Z" }, + { url = "https://files.pythonhosted.org/packages/4e/9d/5e3e362815152aa1afd8b26ea613effa005962f9da0eec6e0e4527e7a7d1/grpcio-1.75.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3e71a2105210366bfc398eef7f57a664df99194f3520edb88b9c3a7e46ee0d64", size = 7081061, upload-time = "2025-09-26T09:02:58.261Z" }, + { url = "https://files.pythonhosted.org/packages/1e/1a/46615682a19e100f46e31ddba9ebc297c5a5ab9ddb47b35443ffadb8776c/grpcio-1.75.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8679aa8a5b67976776d3c6b0521e99d1c34db8a312a12bcfd78a7085cb9b604e", size = 8010849, upload-time = "2025-09-26T09:03:00.548Z" }, + { url = "https://files.pythonhosted.org/packages/67/8e/3204b94ac30b0f675ab1c06540ab5578660dc8b690db71854d3116f20d00/grpcio-1.75.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:aad1c774f4ebf0696a7f148a56d39a3432550612597331792528895258966dc0", size = 7464478, upload-time = "2025-09-26T09:03:03.096Z" }, + { url = "https://files.pythonhosted.org/packages/b7/97/2d90652b213863b2cf466d9c1260ca7e7b67a16780431b3eb1d0420e3d5b/grpcio-1.75.1-cp314-cp314-win32.whl", hash = "sha256:62ce42d9994446b307649cb2a23335fa8e927f7ab2cbf5fcb844d6acb4d85f9c", size = 4012672, upload-time = "2025-09-26T09:03:05.477Z" }, + { url = "https://files.pythonhosted.org/packages/f9/df/e2e6e9fc1c985cd1a59e6996a05647c720fe8a03b92f5ec2d60d366c531e/grpcio-1.75.1-cp314-cp314-win_amd64.whl", hash = "sha256:f86e92275710bea3000cb79feca1762dc0ad3b27830dd1a74e82ab321d4ee464", size = 4772475, upload-time = "2025-09-26T09:03:07.661Z" }, +] + +[[package]] +name = "grpcio-status" +version = "1.75.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "grpcio" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/5b/1ce0e3eedcdc08b4739b3da5836f31142ec8bee1a9ae0ad8dc0dc39a14bf/grpcio_status-1.75.1.tar.gz", hash = "sha256:8162afa21833a2085c91089cc395ad880fac1378a1d60233d976649ed724cbf8", size = 13671, upload-time = "2025-09-26T09:13:16.412Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/ad/6f414bb0b36eee20d93af6907256f208ffcda992ae6d3d7b6a778afe31e6/grpcio_status-1.75.1-py3-none-any.whl", hash = "sha256:f681b301be26dcf7abf5c765d4a22e4098765e1a65cbdfa3efca384edf8e4e3c", size = 14428, upload-time = "2025-09-26T09:12:55.516Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "importlib-resources" +version = "6.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, +] + +[[package]] +name = "inflect" +version = "7.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "more-itertools" }, + { name = "typeguard" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/c6/943357d44a21fd995723d07ccaddd78023eace03c1846049a2645d4324a3/inflect-7.5.0.tar.gz", hash = "sha256:faf19801c3742ed5a05a8ce388e0d8fe1a07f8d095c82201eb904f5d27ad571f", size = 73751, upload-time = "2024-12-28T17:11:18.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/eb/427ed2b20a38a4ee29f24dbe4ae2dafab198674fe9a85e3d6adf9e5f5f41/inflect-7.5.0-py3-none-any.whl", hash = "sha256:2aea70e5e70c35d8350b8097396ec155ffd68def678c7ff97f51aa69c1d92344", size = 35197, upload-time = "2024-12-28T17:11:15.931Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + +[[package]] +name = "isort" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/82/fa43935523efdfcce6abbae9da7f372b627b27142c3419fcf13bf5b0c397/isort-6.1.0.tar.gz", hash = "sha256:9b8f96a14cfee0677e78e941ff62f03769a06d412aabb9e2a90487b3b7e8d481", size = 824325, upload-time = "2025-10-01T16:26:45.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/cc/9b681a170efab4868a032631dea1e8446d8ec718a7f657b94d49d1a12643/isort-6.1.0-py3-none-any.whl", hash = "sha256:58d8927ecce74e5087aef019f778d4081a3b6c98f15a80ba35782ca8a2097784", size = 94329, upload-time = "2025-10-01T16:26:43.291Z" }, +] + +[[package]] +name = "itsdangerous" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jmespath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "lmdb" +version = "1.7.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/87/b6f8bccab1ec1fe58866108c0da648715bc1488627edf9702dae6380613a/lmdb-1.7.3.tar.gz", hash = "sha256:d4a27b7af4fe38f3409d9fbfbf47b617b3d94dee98a00bc8c2a8336ccd3f9b15", size = 883449, upload-time = "2025-07-26T01:11:43.197Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/7c/3e90eeca144c430cc994a9b575215cd5a902327e248eede790ccc1731503/lmdb-1.7.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a0c9d7b35adf001884687ca0c256f6c97aedfcc8bb118da92dcdef41e025cb92", size = 101186, upload-time = "2025-07-26T01:11:02.513Z" }, + { url = "https://files.pythonhosted.org/packages/95/69/8e7542c81413f850ac0b7bc286fb50ea07f7fbed72c797788d8198c70531/lmdb-1.7.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0522361cb78bc9e43003689f2dd3842e4ff8a9a8c11d41b942396f7b94602109", size = 98575, upload-time = "2025-07-26T01:11:03.661Z" }, + { url = "https://files.pythonhosted.org/packages/99/c5/9e6d150f0070908e70ccae4dde5d2fc970a9de83b6ccd8214383bfb2b050/lmdb-1.7.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92ee64c2de8185def1eac0d6272626cb57443895b5cd6f35eda848c0426e678e", size = 299883, upload-time = "2025-07-26T01:11:04.795Z" }, + { url = "https://files.pythonhosted.org/packages/bc/02/98d3d0487aebfaa8fba1ced51bd73f86186293c698f36de585d65e6e8487/lmdb-1.7.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50438f2b333f53539805d3565c0049507e743dff6280229980f1717ef5fcb0ac", size = 302994, upload-time = "2025-07-26T01:11:06.52Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d7/e30633a116b8e3a887883e2ad7aea4231e67d47d9b1a6827a9a0d7d5aa45/lmdb-1.7.3-cp312-cp312-win_amd64.whl", hash = "sha256:a2cef8c30b6d5138ef2f7ed1fff661c497f988c5c7e38699295502bfd148a9ce", size = 99325, upload-time = "2025-07-26T01:11:07.881Z" }, + { url = "https://files.pythonhosted.org/packages/10/5c/d417ac692eca2dcd5b2a8460389fa8883b5d7aafbccc0e48a206c6606365/lmdb-1.7.3-cp312-cp312-win_arm64.whl", hash = "sha256:4aa31d12b16fa0d4ab5d49a347a352eb65f8887ae52e9bfe1811b5daff83a064", size = 94184, upload-time = "2025-07-26T01:11:09.254Z" }, + { url = "https://files.pythonhosted.org/packages/57/e8/2f89d1f2a1fd665dc663029dbeb19b9aa7e8fabaaa1491108112bcc44620/lmdb-1.7.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3ef46b01b09afe8193449330ea6c0350891d1cdc43cbd20aec8ecdbe40def7d1", size = 101916, upload-time = "2025-07-26T01:11:10.432Z" }, + { url = "https://files.pythonhosted.org/packages/c5/57/e17901d6f0da20da6795d7fda35a68416b4b14e84873039c4b87870d45c6/lmdb-1.7.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:88d9b76a11e7458801064df8c837fe23ca28b714205dce05f17a58da3777db6a", size = 99340, upload-time = "2025-07-26T01:11:11.752Z" }, + { url = "https://files.pythonhosted.org/packages/b8/b7/7bfc65b5003ecc7f41fe6d4aeb3e425746cb2eda05d7314f712fca6d6094/lmdb-1.7.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39dd69f3dc0910ed15ed5db708f195dc3c7f3275d1fb1a8f0a2a4b31db69cdd0", size = 301234, upload-time = "2025-07-26T01:11:12.951Z" }, + { url = "https://files.pythonhosted.org/packages/68/65/b2e8aa0ddc984f3b8cf72223d878f0d7ff70f1744ad34b4917bc63b7dfe0/lmdb-1.7.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad0dbec5586bb991c9ab05f5a26d950e8fa3583e632baf2604512f8059028139", size = 304101, upload-time = "2025-07-26T01:11:14.103Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ea/059050689e8ad6c859d8bb7d88c7b4c183a7d54c6079aa6601e0935449ba/lmdb-1.7.3-cp313-cp313-win_amd64.whl", hash = "sha256:d25279380b28f01f8f1ef0f783488808bfc2b657c1705c6f383b77c9d04cd8a6", size = 99447, upload-time = "2025-07-26T01:11:15.606Z" }, + { url = "https://files.pythonhosted.org/packages/ad/38/b9e7e5807dbeaf66cd3326161f03ba2274c0774da15f213745708c30d924/lmdb-1.7.3-cp313-cp313-win_arm64.whl", hash = "sha256:1f22e79cc7cebc643c20f1699092bddb6d648d959f4f73becce0befb52690c97", size = 94146, upload-time = "2025-07-26T01:11:16.943Z" }, + { url = "https://files.pythonhosted.org/packages/b9/ab/e6c2ba79107d20c7a45eae2d69e395691635e761b1e57f5a29c5f2fc42ff/lmdb-1.7.3-py3-none-any.whl", hash = "sha256:4cd7fb79b2c69dcf564d4eec36237e0efc303559176b60ff36fb47ccd3b8b5bb", size = 148538, upload-time = "2025-07-26T01:11:42.118Z" }, +] + +[[package]] +name = "loro" +version = "1.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/be/4e00ced4b8f2d852dc581109de9b4cd9362395e276b509eece098c42eedd/loro-1.8.1.tar.gz", hash = "sha256:22cfb19625bd7245e9747ee9d43b10511c16a35775a38cf914dc74863c4dbe88", size = 64093, upload-time = "2025-09-23T15:53:20.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/e1/2d381182a111ca8cf4f4869bcf43e68c4ebabf1d84da4a08eda355834547/loro-1.8.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9eeab61cac92d504eecd580c577becc12a0a3830141b17a49812ecaf5d3f3ebf", size = 3088136, upload-time = "2025-09-23T15:50:35.106Z" }, + { url = "https://files.pythonhosted.org/packages/3f/9c/00a5476efb54b1091145ed3c7dc0d5961f283b407e7608b649d00ded4a28/loro-1.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1f08fa1b4bdc79901c763d81361537ca5c086560acb80291f5d6fe163613c603", size = 2878906, upload-time = "2025-09-23T15:50:19.017Z" }, + { url = "https://files.pythonhosted.org/packages/c6/5e/e55ba22e04313979c4f0eb74db1100c179c592d99cb0e514e60a155bbf02/loro-1.8.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420fb0112115dc85b8abd392e18aa163c7fda72b5329be46e7d0cb2261ef8adc", size = 3114935, upload-time = "2025-09-23T15:46:49.989Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f0/55deb84ed33d1d8a4f45c112bcb36d00701d8c94bf3f2071e610a993b36e/loro-1.8.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:97153d8929cda5903fdd5d681a5d0d4a28382e2707b292cfad6a387f4b73396c", size = 3181672, upload-time = "2025-09-23T15:47:27.898Z" }, + { url = "https://files.pythonhosted.org/packages/be/05/181f8051b2142c28e5cf294ac5f13b34bb3e3e802d256842010e05c29596/loro-1.8.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:934362a533d0ebf75216799f1305252502a2e9733b3a7bb311012c4b8495f541", size = 3567186, upload-time = "2025-09-23T15:48:06.357Z" }, + { url = "https://files.pythonhosted.org/packages/03/9b/e91146ad0a0cfb73bd47f39e69685ab3e8654aa17875f1806ba484be88ef/loro-1.8.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7c777cd9ddc13cde9d0ec887ae3e02879d2f861d5862a0b6efd29fe4eff30dc", size = 3286193, upload-time = "2025-09-23T15:48:41.849Z" }, + { url = "https://files.pythonhosted.org/packages/da/2e/c07116cf6a22dbcb5d7d7d693b184358f8a59737290076c98108f17ffb29/loro-1.8.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca9d40e6e65d748d36867fa623275d3b3bdb7c1da68f4005bc17f69a57034c0", size = 3177660, upload-time = "2025-09-23T15:49:48.468Z" }, + { url = "https://files.pythonhosted.org/packages/83/05/8ec0261ac604b76a716c0f57afbf5454448b1d82f0a06c99972ae89e28de/loro-1.8.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca5bd845dc9b880a3fcbe1c977549157ed3e22566a38ee3d4bd94bfd76e12e50", size = 3507836, upload-time = "2025-09-23T15:49:19.107Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b6/1be760344ca3f9cff3732b6d4ea0c03a9118b479074568bd9908dc935b30/loro-1.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:48884003f2268d83864205445ac8302894c0f51c63c7d8375c4ffd8e100e7ced", size = 3295335, upload-time = "2025-09-23T15:50:52.636Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f6/b6362dc3103e45e4f3680d6c8df44c7f5a3e266c3940119956b0120e1b7a/loro-1.8.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7392c983eb8c6fa062925dcca583dd2d635ea16105153b0cea3a0f40333bf60c", size = 3444357, upload-time = "2025-09-23T15:51:30.694Z" }, + { url = "https://files.pythonhosted.org/packages/98/4b/9c7537846bb6d2a1267adcabd202f02a3c3fa7a3fbcf6537106574fc8fd9/loro-1.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:03f9e0ea6c72929cacebef44e698db50e0e9caa77cc4d87d43a5b5836896a5a3", size = 3489985, upload-time = "2025-09-23T15:52:08.234Z" }, + { url = "https://files.pythonhosted.org/packages/7a/8a/66b7859080d9017ecae74d7835fe2419dfd27435382195d508644530b141/loro-1.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e0a0188d120bce70a64c58731330ed9b495ae2034061b5a3616b2b7940ead89", size = 3393867, upload-time = "2025-09-23T15:52:44.75Z" }, + { url = "https://files.pythonhosted.org/packages/ed/9e/7c83206c10f8cb38532da00f0814cac0e6207956a6a39e5e183227cece21/loro-1.8.1-cp312-cp312-win32.whl", hash = "sha256:90a02ac5c85629d920c4767dc4b31382d21bde7af93d5dc4d3a4fcde4b4fece0", size = 2597517, upload-time = "2025-09-23T15:53:46.401Z" }, + { url = "https://files.pythonhosted.org/packages/af/86/4357a818e5a03d1be1fa62cc1c0591b19b8a5e71dd00d45a7f8e8b48b28a/loro-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:92a31a8613fc6d9bb33a64767202e19592ac670618a174c0fbc940e31dba9d87", size = 2741953, upload-time = "2025-09-23T15:53:24.587Z" }, + { url = "https://files.pythonhosted.org/packages/f9/7c/e0f6d6376dedb504e826b09a71bb871f4c032c2c95db0f96ee9f1b463a17/loro-1.8.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:55ee9ded98d6e328f210a1b9e2f01e8befb6994da82dd03756c56d8aa047a2ce", size = 3088156, upload-time = "2025-09-23T15:50:37.613Z" }, + { url = "https://files.pythonhosted.org/packages/7b/3c/9fa9fd4a244539943df17c4fb3e3c5e90f0726731b9bf59bfbd9e57b09bb/loro-1.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4dcc9a3f558912d0ba2d39954f8391084e987e7970b375bfd96f67d9499ad4a0", size = 2879185, upload-time = "2025-09-23T15:50:20.352Z" }, + { url = "https://files.pythonhosted.org/packages/5b/f2/48ab3634a1dc3f5951e05905d93c7e9dc2061d93e1facf6896f0d385cb61/loro-1.8.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a2b318bb08d1bdc7a0b8467a7ec6d90c7c46b0c58e7aafc9fc307825fa868f7", size = 3115017, upload-time = "2025-09-23T15:46:51.372Z" }, + { url = "https://files.pythonhosted.org/packages/00/a1/7a80b48fca9366cb6867e4394b80dae7db9044e3f1e8ed586d5dfc467c2c/loro-1.8.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42a7e09cb68da97559cd103a93ae69004bb929fba3db6a13846c83ac979698ce", size = 3181487, upload-time = "2025-09-23T15:47:29.219Z" }, + { url = "https://files.pythonhosted.org/packages/50/f9/881d9a4658f5d33ac822735ee503d8e5590db552a1ac3f992a36a4fae03d/loro-1.8.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cc5acb22ca0ae3e6793024cfc3ea99f200b57c549fa71e48cdaedf22cde6fe19", size = 3566686, upload-time = "2025-09-23T15:48:07.701Z" }, + { url = "https://files.pythonhosted.org/packages/be/6b/3ff95d187483b0f71e026e86a3b3043e27048d9a554777254b8005f396c8/loro-1.8.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc92b19a44b16e86dced2b76d760715f1099aa99433c908e0fe5627d7897b98d", size = 3286348, upload-time = "2025-09-23T15:48:43.416Z" }, + { url = "https://files.pythonhosted.org/packages/31/03/414915e26d2463107425f3ff249a2f992f2b15d0f98d75c99422fc34eb48/loro-1.8.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eed7933a3e1500c5a8e826c5faf7904ce253725512234eb2b2bfb01ca085217", size = 3177439, upload-time = "2025-09-23T15:49:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/d0/25/538488ceb0a7b857eadecc4e46c6bea20df2b9f6ad1660ad6d10b201d931/loro-1.8.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e62783de33f8bf0cf8b834defacd4dd62d1adb227d93d9d24cc28febf9f53eec", size = 3508131, upload-time = "2025-09-23T15:49:20.534Z" }, + { url = "https://files.pythonhosted.org/packages/6a/f0/8c06a5ae198c7fdc636fd40cf6edc604b45e51affbd537d099eb93a95143/loro-1.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8f394e65acd54af19b5cea796d9d9aa4e512f7979f8514f6938fd9813a753f5", size = 3295009, upload-time = "2025-09-23T15:50:54.272Z" }, + { url = "https://files.pythonhosted.org/packages/bf/4a/2fb82afaab5899cc3a05d31e4059aded41571e6fd5c310cb5bc5520c563f/loro-1.8.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6205cc3fcb75b4913678ca399ab97abab0f253c8f72ece637d183979c06d19a1", size = 3444600, upload-time = "2025-09-23T15:51:32.046Z" }, + { url = "https://files.pythonhosted.org/packages/f6/87/4b9ac56d371c7a4b85ea223ca17b7ab33de858dab8a1a176ad33af9d7cb7/loro-1.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b1cd5d028309f8ae94b14b7b1fb3a6e488b8a09d205a37d44eb3af04061be742", size = 3489090, upload-time = "2025-09-23T15:52:09.704Z" }, + { url = "https://files.pythonhosted.org/packages/32/90/abf2a9f9f6c0cfd6ccb940fa81d9561767d01d43684505884e404ee4e930/loro-1.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3da7bc3cc0e8b04f094bc52c3f416f86be4c3a332dcbd9428b466d98329f26f5", size = 3393536, upload-time = "2025-09-23T15:52:46.284Z" }, + { url = "https://files.pythonhosted.org/packages/4a/34/76136846dc793e96a34f73220d65279f7b7f391a3446838fd095bf804d73/loro-1.8.1-cp313-cp313-win32.whl", hash = "sha256:a90e5d56a030e284a998b73a1c55c5b8c5f62f96bee4cc017b88ff815f9fb743", size = 2598079, upload-time = "2025-09-23T15:53:47.994Z" }, + { url = "https://files.pythonhosted.org/packages/f5/6e/dfd0d18a7bd7d90b111cde4e628e0fc26d70307caae33f3ee6d28094125b/loro-1.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:fbee625170327de616709af943410b72c5a4c12ebd8f7dff6324d59aa51da5b2", size = 2742638, upload-time = "2025-09-23T15:53:26.074Z" }, + { url = "https://files.pythonhosted.org/packages/6c/ac/e134286c4275af5ab0149ee1a200c64f35df2cccb1b70142af04b509ed7f/loro-1.8.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df6f3dfa58cebfe1f0e08a8a929303338c506733dd8650afd3d1f3ac70546ece", size = 3109397, upload-time = "2025-09-23T15:46:53.148Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ee/578a588f5f0a642491b852d0bc7bbec90e6a93fa95b12c4e22e7514d156e/loro-1.8.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c632a0a4a00f4a73df32fcaf266320995f89b68fc5f1d875efc979cda810babd", size = 3182019, upload-time = "2025-09-23T15:47:30.88Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b6/6b8932e77fb6563fcab5ce470a3b754a758b8ce743a389b14ba9c436cd5d/loro-1.8.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:888de919b082ace4cb88f7244aa7a5263233604fc0fb9e7571703940a6897be2", size = 3562136, upload-time = "2025-09-23T15:48:09.165Z" }, + { url = "https://files.pythonhosted.org/packages/3d/a6/440e9ff25150908e9e91362fed32097c008956ff173e9d852adfd06ce25f/loro-1.8.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1689f8fd79dc76f75e4bd027e9685bb73b44e0b60cfc0412d78369da300e6f68", size = 3283645, upload-time = "2025-09-23T15:48:44.959Z" }, + { url = "https://files.pythonhosted.org/packages/f3/3d/4444939a3d244242dbcc14c98789c7c89d2468cb541629695335a953cbc3/loro-1.8.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:028194142bc4b628ec0f926018fbfd18d92912d69eb2f57a14adf4a3ef1fc7e7", size = 3288947, upload-time = "2025-09-23T15:50:55.972Z" }, + { url = "https://files.pythonhosted.org/packages/2a/43/70201ccf7b57f172ee1bb4d14fc7194359802aa17c1ac1608d503c19ee47/loro-1.8.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:9e6dde01971d72ba678161aaa24bc5261929def86a6feb8149d3e2dab0964aea", size = 3444718, upload-time = "2025-09-23T15:51:33.872Z" }, + { url = "https://files.pythonhosted.org/packages/14/b8/01c1d4339ab67d8aff6a5038db6251f6d44967a663f2692be6aabe276035/loro-1.8.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8d3789752b26b40f26a44a80d784a4f9e40f2bd0e40a4eeb01e1e386920feaaa", size = 3490418, upload-time = "2025-09-23T15:52:11.183Z" }, + { url = "https://files.pythonhosted.org/packages/60/67/88e0edaf4158184d87eee4efdce283306831632ef7ef010153abf6d36b82/loro-1.8.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ab04743218b6cbbfdf4ca74d158aed20ed0c9d7019620d35548e89f1d519923b", size = 3389761, upload-time = "2025-09-23T15:52:47.785Z" }, + { url = "https://files.pythonhosted.org/packages/54/fb/ccf317276518df910340ddf7729a0ed1602d215db1f6ca8ccda0fc6071df/loro-1.8.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:29c25f33c659a8027974cd88c94f08b4708376b200290a858c8abd891d64ba15", size = 3072231, upload-time = "2025-09-23T15:50:43.568Z" }, + { url = "https://files.pythonhosted.org/packages/bd/5c/87f37c4bbef478373b15ad4052ab9ee69ae87646a9c853dda97147f4e87a/loro-1.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a9643d19eee7379b6980fc3b31a492bd22aa1e9aaa6fd67c8b5b4b57a0c7a1c", size = 2870631, upload-time = "2025-09-23T15:50:26.223Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7f/b0d121297000d1278c4be96ebaed245b7e1edf74851b9ed5aa552daf85eb/loro-1.8.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:323370115c37a793e805952e21703d8e8c91cc7ef16dd3a378043fe40174599f", size = 3156119, upload-time = "2025-09-23T15:49:51.227Z" }, + { url = "https://files.pythonhosted.org/packages/70/ee/35c62e7acfc572397ffb09db60f20b32be422a7983ae3d891527983a6a7e/loro-1.8.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:69265d6751e536fd7ba1f04c6be200239b4d8090bcd1325a95ded08621c4c910", size = 3492080, upload-time = "2025-09-23T15:49:22.137Z" }, + { url = "https://files.pythonhosted.org/packages/23/36/543916bb43228e4d13e155d9f31cbe16cf4f995d306aa5dbf4aba2b44170/loro-1.8.1-cp314-cp314-win32.whl", hash = "sha256:00c3662f50b81276a0f45d90504402e36512fda9f98e3e9353cc2b2394aa56a5", size = 2584938, upload-time = "2025-09-23T15:53:49.355Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b1/8369c393107cafcaf6d5bdfe8cc4fead384b8ab8c7ddaf5d16235e5482e2/loro-1.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:c6ebacceed553dad118dd61f946f5f8fb23ace5ca93e8ee8ebd4f6ca4cffa854", size = 2722278, upload-time = "2025-09-23T15:53:36.035Z" }, +] + +[[package]] +name = "lz4" +version = "4.4.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/51/f1b86d93029f418033dddf9b9f79c8d2641e7454080478ee2aab5123173e/lz4-4.4.5.tar.gz", hash = "sha256:5f0b9e53c1e82e88c10d7c180069363980136b9d7a8306c4dca4f760d60c39f0", size = 172886, upload-time = "2025-11-03T13:02:36.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/ac/016e4f6de37d806f7cc8f13add0a46c9a7cfc41a5ddc2bc831d7954cf1ce/lz4-4.4.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:df5aa4cead2044bab83e0ebae56e0944cc7fcc1505c7787e9e1057d6d549897e", size = 207163, upload-time = "2025-11-03T13:01:45.895Z" }, + { url = "https://files.pythonhosted.org/packages/8d/df/0fadac6e5bd31b6f34a1a8dbd4db6a7606e70715387c27368586455b7fc9/lz4-4.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d0bf51e7745484d2092b3a51ae6eb58c3bd3ce0300cf2b2c14f76c536d5697a", size = 207150, upload-time = "2025-11-03T13:01:47.205Z" }, + { url = "https://files.pythonhosted.org/packages/b7/17/34e36cc49bb16ca73fb57fbd4c5eaa61760c6b64bce91fcb4e0f4a97f852/lz4-4.4.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7b62f94b523c251cf32aa4ab555f14d39bd1a9df385b72443fd76d7c7fb051f5", size = 1292045, upload-time = "2025-11-03T13:01:48.667Z" }, + { url = "https://files.pythonhosted.org/packages/90/1c/b1d8e3741e9fc89ed3b5f7ef5f22586c07ed6bb04e8343c2e98f0fa7ff04/lz4-4.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c3ea562c3af274264444819ae9b14dbbf1ab070aff214a05e97db6896c7597e", size = 1279546, upload-time = "2025-11-03T13:01:50.159Z" }, + { url = "https://files.pythonhosted.org/packages/55/d9/e3867222474f6c1b76e89f3bd914595af69f55bf2c1866e984c548afdc15/lz4-4.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24092635f47538b392c4eaeff14c7270d2c8e806bf4be2a6446a378591c5e69e", size = 1368249, upload-time = "2025-11-03T13:01:51.273Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e7/d667d337367686311c38b580d1ca3d5a23a6617e129f26becd4f5dc458df/lz4-4.4.5-cp312-cp312-win32.whl", hash = "sha256:214e37cfe270948ea7eb777229e211c601a3e0875541c1035ab408fbceaddf50", size = 88189, upload-time = "2025-11-03T13:01:52.605Z" }, + { url = "https://files.pythonhosted.org/packages/a5/0b/a54cd7406995ab097fceb907c7eb13a6ddd49e0b231e448f1a81a50af65c/lz4-4.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:713a777de88a73425cf08eb11f742cd2c98628e79a8673d6a52e3c5f0c116f33", size = 99497, upload-time = "2025-11-03T13:01:53.477Z" }, + { url = "https://files.pythonhosted.org/packages/6a/7e/dc28a952e4bfa32ca16fa2eb026e7a6ce5d1411fcd5986cd08c74ec187b9/lz4-4.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:a88cbb729cc333334ccfb52f070463c21560fca63afcf636a9f160a55fac3301", size = 91279, upload-time = "2025-11-03T13:01:54.419Z" }, + { url = "https://files.pythonhosted.org/packages/2f/46/08fd8ef19b782f301d56a9ccfd7dafec5fd4fc1a9f017cf22a1accb585d7/lz4-4.4.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6bb05416444fafea170b07181bc70640975ecc2a8c92b3b658c554119519716c", size = 207171, upload-time = "2025-11-03T13:01:56.595Z" }, + { url = "https://files.pythonhosted.org/packages/8f/3f/ea3334e59de30871d773963997ecdba96c4584c5f8007fd83cfc8f1ee935/lz4-4.4.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b424df1076e40d4e884cfcc4c77d815368b7fb9ebcd7e634f937725cd9a8a72a", size = 207163, upload-time = "2025-11-03T13:01:57.721Z" }, + { url = "https://files.pythonhosted.org/packages/41/7b/7b3a2a0feb998969f4793c650bb16eff5b06e80d1f7bff867feb332f2af2/lz4-4.4.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:216ca0c6c90719731c64f41cfbd6f27a736d7e50a10b70fad2a9c9b262ec923d", size = 1292136, upload-time = "2025-11-03T13:02:00.375Z" }, + { url = "https://files.pythonhosted.org/packages/89/d1/f1d259352227bb1c185288dd694121ea303e43404aa77560b879c90e7073/lz4-4.4.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:533298d208b58b651662dd972f52d807d48915176e5b032fb4f8c3b6f5fe535c", size = 1279639, upload-time = "2025-11-03T13:02:01.649Z" }, + { url = "https://files.pythonhosted.org/packages/d2/fb/ba9256c48266a09012ed1d9b0253b9aa4fe9cdff094f8febf5b26a4aa2a2/lz4-4.4.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:451039b609b9a88a934800b5fc6ee401c89ad9c175abf2f4d9f8b2e4ef1afc64", size = 1368257, upload-time = "2025-11-03T13:02:03.35Z" }, + { url = "https://files.pythonhosted.org/packages/a5/6d/dee32a9430c8b0e01bbb4537573cabd00555827f1a0a42d4e24ca803935c/lz4-4.4.5-cp313-cp313-win32.whl", hash = "sha256:a5f197ffa6fc0e93207b0af71b302e0a2f6f29982e5de0fbda61606dd3a55832", size = 88191, upload-time = "2025-11-03T13:02:04.406Z" }, + { url = "https://files.pythonhosted.org/packages/18/e0/f06028aea741bbecb2a7e9648f4643235279a770c7ffaf70bd4860c73661/lz4-4.4.5-cp313-cp313-win_amd64.whl", hash = "sha256:da68497f78953017deb20edff0dba95641cc86e7423dfadf7c0264e1ac60dc22", size = 99502, upload-time = "2025-11-03T13:02:05.886Z" }, + { url = "https://files.pythonhosted.org/packages/61/72/5bef44afb303e56078676b9f2486f13173a3c1e7f17eaac1793538174817/lz4-4.4.5-cp313-cp313-win_arm64.whl", hash = "sha256:c1cfa663468a189dab510ab231aad030970593f997746d7a324d40104db0d0a9", size = 91285, upload-time = "2025-11-03T13:02:06.77Z" }, + { url = "https://files.pythonhosted.org/packages/49/55/6a5c2952971af73f15ed4ebfdd69774b454bd0dc905b289082ca8664fba1/lz4-4.4.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67531da3b62f49c939e09d56492baf397175ff39926d0bd5bd2d191ac2bff95f", size = 207348, upload-time = "2025-11-03T13:02:08.117Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d7/fd62cbdbdccc35341e83aabdb3f6d5c19be2687d0a4eaf6457ddf53bba64/lz4-4.4.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a1acbbba9edbcbb982bc2cac5e7108f0f553aebac1040fbec67a011a45afa1ba", size = 207340, upload-time = "2025-11-03T13:02:09.152Z" }, + { url = "https://files.pythonhosted.org/packages/77/69/225ffadaacb4b0e0eb5fd263541edd938f16cd21fe1eae3cd6d5b6a259dc/lz4-4.4.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a482eecc0b7829c89b498fda883dbd50e98153a116de612ee7c111c8bcf82d1d", size = 1293398, upload-time = "2025-11-03T13:02:10.272Z" }, + { url = "https://files.pythonhosted.org/packages/c6/9e/2ce59ba4a21ea5dc43460cba6f34584e187328019abc0e66698f2b66c881/lz4-4.4.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e099ddfaa88f59dd8d36c8a3c66bd982b4984edf127eb18e30bb49bdba68ce67", size = 1281209, upload-time = "2025-11-03T13:02:12.091Z" }, + { url = "https://files.pythonhosted.org/packages/80/4f/4d946bd1624ec229b386a3bc8e7a85fa9a963d67d0a62043f0af0978d3da/lz4-4.4.5-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2af2897333b421360fdcce895c6f6281dc3fab018d19d341cf64d043fc8d90d", size = 1369406, upload-time = "2025-11-03T13:02:13.683Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/d429ba4720a9064722698b4b754fb93e42e625f1318b8fe834086c7c783b/lz4-4.4.5-cp313-cp313t-win32.whl", hash = "sha256:66c5de72bf4988e1b284ebdd6524c4bead2c507a2d7f172201572bac6f593901", size = 88325, upload-time = "2025-11-03T13:02:14.743Z" }, + { url = "https://files.pythonhosted.org/packages/4b/85/7ba10c9b97c06af6c8f7032ec942ff127558863df52d866019ce9d2425cf/lz4-4.4.5-cp313-cp313t-win_amd64.whl", hash = "sha256:cdd4bdcbaf35056086d910d219106f6a04e1ab0daa40ec0eeef1626c27d0fddb", size = 99643, upload-time = "2025-11-03T13:02:15.978Z" }, + { url = "https://files.pythonhosted.org/packages/77/4d/a175459fb29f909e13e57c8f475181ad8085d8d7869bd8ad99033e3ee5fa/lz4-4.4.5-cp313-cp313t-win_arm64.whl", hash = "sha256:28ccaeb7c5222454cd5f60fcd152564205bcb801bd80e125949d2dfbadc76bbd", size = 91504, upload-time = "2025-11-03T13:02:17.313Z" }, + { url = "https://files.pythonhosted.org/packages/63/9c/70bdbdb9f54053a308b200b4678afd13efd0eafb6ddcbb7f00077213c2e5/lz4-4.4.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c216b6d5275fc060c6280936bb3bb0e0be6126afb08abccde27eed23dead135f", size = 207586, upload-time = "2025-11-03T13:02:18.263Z" }, + { url = "https://files.pythonhosted.org/packages/b6/cb/bfead8f437741ce51e14b3c7d404e3a1f6b409c440bad9b8f3945d4c40a7/lz4-4.4.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c8e71b14938082ebaf78144f3b3917ac715f72d14c076f384a4c062df96f9df6", size = 207161, upload-time = "2025-11-03T13:02:19.286Z" }, + { url = "https://files.pythonhosted.org/packages/e7/18/b192b2ce465dfbeabc4fc957ece7a1d34aded0d95a588862f1c8a86ac448/lz4-4.4.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b5e6abca8df9f9bdc5c3085f33ff32cdc86ed04c65e0355506d46a5ac19b6e9", size = 1292415, upload-time = "2025-11-03T13:02:20.829Z" }, + { url = "https://files.pythonhosted.org/packages/67/79/a4e91872ab60f5e89bfad3e996ea7dc74a30f27253faf95865771225ccba/lz4-4.4.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b84a42da86e8ad8537aabef062e7f661f4a877d1c74d65606c49d835d36d668", size = 1279920, upload-time = "2025-11-03T13:02:22.013Z" }, + { url = "https://files.pythonhosted.org/packages/f1/01/d52c7b11eaa286d49dae619c0eec4aabc0bf3cda7a7467eb77c62c4471f3/lz4-4.4.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bba042ec5a61fa77c7e380351a61cb768277801240249841defd2ff0a10742f", size = 1368661, upload-time = "2025-11-03T13:02:23.208Z" }, + { url = "https://files.pythonhosted.org/packages/f7/da/137ddeea14c2cb86864838277b2607d09f8253f152156a07f84e11768a28/lz4-4.4.5-cp314-cp314-win32.whl", hash = "sha256:bd85d118316b53ed73956435bee1997bd06cc66dd2fa74073e3b1322bd520a67", size = 90139, upload-time = "2025-11-03T13:02:24.301Z" }, + { url = "https://files.pythonhosted.org/packages/18/2c/8332080fd293f8337779a440b3a143f85e374311705d243439a3349b81ad/lz4-4.4.5-cp314-cp314-win_amd64.whl", hash = "sha256:92159782a4502858a21e0079d77cdcaade23e8a5d252ddf46b0652604300d7be", size = 101497, upload-time = "2025-11-03T13:02:25.187Z" }, + { url = "https://files.pythonhosted.org/packages/ca/28/2635a8141c9a4f4bc23f5135a92bbcf48d928d8ca094088c962df1879d64/lz4-4.4.5-cp314-cp314-win_arm64.whl", hash = "sha256:d994b87abaa7a88ceb7a37c90f547b8284ff9da694e6afcfaa8568d739faf3f7", size = 93812, upload-time = "2025-11-03T13:02:26.133Z" }, +] + +[[package]] +name = "marimo" +version = "0.16.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "docutils" }, + { name = "itsdangerous" }, + { name = "jedi" }, + { name = "loro" }, + { name = "markdown" }, + { name = "msgspec" }, + { name = "narwhals" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "pyyaml" }, + { name = "starlette" }, + { name = "tomlkit" }, + { name = "uvicorn" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/67/6b/5e1fcdeebebf6cebfbbf7cd6eda3be1ee019e50c693d99f00e478c4f3f8c/marimo-0.16.5.tar.gz", hash = "sha256:8f5939d3c4e67ff25f6cfeefe731971ed7f3346c20098034b923a24a0d7770d6", size = 33882430, upload-time = "2025-10-02T19:57:49.438Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/a0/14bd2ae122db3c4c43c6ebf0c861196328156f61e6452c2cd67b730430b0/marimo-0.16.5-py3-none-any.whl", hash = "sha256:1f98c0ee0fed9337e26c895c662f92cc578cdd03502c194eac9ceeb434bf479b", size = 34400840, upload-time = "2025-10-02T19:57:45.076Z" }, +] + +[[package]] +name = "markdown" +version = "3.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/ae/44c4a6a4cbb496d93c6257954260fe3a6e91b7bed2240e5dad2a717f5111/markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280", size = 107441, upload-time = "2025-09-04T20:25:21.784Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.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" } +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" }, +] + +[[package]] +name = "markupsafe" +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/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" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "mmh3" +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/af/f28c2c2f51f31abb4725f9a64bc7863d5f491f6539bd26aee2a1d21a649e/mmh3-5.2.0.tar.gz", hash = "sha256:1efc8fec8478e9243a78bb993422cf79f8ff85cb4cf6b79647480a31e0d950a8", size = 33582, upload-time = "2025-07-29T07:43:48.49Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/6a/d5aa7edb5c08e0bd24286c7d08341a0446f9a2fbbb97d96a8a6dd81935ee/mmh3-5.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:384eda9361a7bf83a85e09447e1feafe081034af9dd428893701b959230d84be", size = 56141, upload-time = "2025-07-29T07:42:13.456Z" }, + { url = "https://files.pythonhosted.org/packages/08/49/131d0fae6447bc4a7299ebdb1a6fb9d08c9f8dcf97d75ea93e8152ddf7ab/mmh3-5.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c9da0d568569cc87315cb063486d761e38458b8ad513fedd3dc9263e1b81bcd", size = 40681, upload-time = "2025-07-29T07:42:14.306Z" }, + { url = "https://files.pythonhosted.org/packages/8f/6f/9221445a6bcc962b7f5ff3ba18ad55bba624bacdc7aa3fc0a518db7da8ec/mmh3-5.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86d1be5d63232e6eb93c50881aea55ff06eb86d8e08f9b5417c8c9b10db9db96", size = 40062, upload-time = "2025-07-29T07:42:15.08Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d4/6bb2d0fef81401e0bb4c297d1eb568b767de4ce6fc00890bc14d7b51ecc4/mmh3-5.2.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bf7bee43e17e81671c447e9c83499f53d99bf440bc6d9dc26a841e21acfbe094", size = 97333, upload-time = "2025-07-29T07:42:16.436Z" }, + { url = "https://files.pythonhosted.org/packages/44/e0/ccf0daff8134efbb4fbc10a945ab53302e358c4b016ada9bf97a6bdd50c1/mmh3-5.2.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7aa18cdb58983ee660c9c400b46272e14fa253c675ed963d3812487f8ca42037", size = 103310, upload-time = "2025-07-29T07:42:17.796Z" }, + { url = "https://files.pythonhosted.org/packages/02/63/1965cb08a46533faca0e420e06aff8bbaf9690a6f0ac6ae6e5b2e4544687/mmh3-5.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9d032488fcec32d22be6542d1a836f00247f40f320844dbb361393b5b22773", size = 106178, upload-time = "2025-07-29T07:42:19.281Z" }, + { url = "https://files.pythonhosted.org/packages/c2/41/c883ad8e2c234013f27f92061200afc11554ea55edd1bcf5e1accd803a85/mmh3-5.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1861fb6b1d0453ed7293200139c0a9011eeb1376632e048e3766945b13313c5", size = 113035, upload-time = "2025-07-29T07:42:20.356Z" }, + { url = "https://files.pythonhosted.org/packages/df/b5/1ccade8b1fa625d634a18bab7bf08a87457e09d5ec8cf83ca07cbea9d400/mmh3-5.2.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:99bb6a4d809aa4e528ddfe2c85dd5239b78b9dd14be62cca0329db78505e7b50", size = 120784, upload-time = "2025-07-29T07:42:21.377Z" }, + { url = "https://files.pythonhosted.org/packages/77/1c/919d9171fcbdcdab242e06394464ccf546f7d0f3b31e0d1e3a630398782e/mmh3-5.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1f8d8b627799f4e2fcc7c034fed8f5f24dc7724ff52f69838a3d6d15f1ad4765", size = 99137, upload-time = "2025-07-29T07:42:22.344Z" }, + { url = "https://files.pythonhosted.org/packages/66/8a/1eebef5bd6633d36281d9fc83cf2e9ba1ba0e1a77dff92aacab83001cee4/mmh3-5.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b5995088dd7023d2d9f310a0c67de5a2b2e06a570ecfd00f9ff4ab94a67cde43", size = 98664, upload-time = "2025-07-29T07:42:23.269Z" }, + { url = "https://files.pythonhosted.org/packages/13/41/a5d981563e2ee682b21fb65e29cc0f517a6734a02b581359edd67f9d0360/mmh3-5.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1a5f4d2e59d6bba8ef01b013c472741835ad961e7c28f50c82b27c57748744a4", size = 106459, upload-time = "2025-07-29T07:42:24.238Z" }, + { url = "https://files.pythonhosted.org/packages/24/31/342494cd6ab792d81e083680875a2c50fa0c5df475ebf0b67784f13e4647/mmh3-5.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fd6e6c3d90660d085f7e73710eab6f5545d4854b81b0135a3526e797009dbda3", size = 110038, upload-time = "2025-07-29T07:42:25.629Z" }, + { url = "https://files.pythonhosted.org/packages/28/44/efda282170a46bb4f19c3e2b90536513b1d821c414c28469a227ca5a1789/mmh3-5.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c4a2f3d83879e3de2eb8cbf562e71563a8ed15ee9b9c2e77ca5d9f73072ac15c", size = 97545, upload-time = "2025-07-29T07:42:27.04Z" }, + { url = "https://files.pythonhosted.org/packages/68/8f/534ae319c6e05d714f437e7206f78c17e66daca88164dff70286b0e8ea0c/mmh3-5.2.0-cp312-cp312-win32.whl", hash = "sha256:2421b9d665a0b1ad724ec7332fb5a98d075f50bc51a6ff854f3a1882bd650d49", size = 40805, upload-time = "2025-07-29T07:42:28.032Z" }, + { url = "https://files.pythonhosted.org/packages/b8/f6/f6abdcfefcedab3c964868048cfe472764ed358c2bf6819a70dd4ed4ed3a/mmh3-5.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:72d80005b7634a3a2220f81fbeb94775ebd12794623bb2e1451701ea732b4aa3", size = 41597, upload-time = "2025-07-29T07:42:28.894Z" }, + { url = "https://files.pythonhosted.org/packages/15/fd/f7420e8cbce45c259c770cac5718badf907b302d3a99ec587ba5ce030237/mmh3-5.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:3d6bfd9662a20c054bc216f861fa330c2dac7c81e7fb8307b5e32ab5b9b4d2e0", size = 39350, upload-time = "2025-07-29T07:42:29.794Z" }, + { url = "https://files.pythonhosted.org/packages/d8/fa/27f6ab93995ef6ad9f940e96593c5dd24744d61a7389532b0fec03745607/mmh3-5.2.0-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:e79c00eba78f7258e5b354eccd4d7907d60317ced924ea4a5f2e9d83f5453065", size = 40874, upload-time = "2025-07-29T07:42:30.662Z" }, + { url = "https://files.pythonhosted.org/packages/11/9c/03d13bcb6a03438bc8cac3d2e50f80908d159b31a4367c2e1a7a077ded32/mmh3-5.2.0-cp313-cp313-android_21_x86_64.whl", hash = "sha256:956127e663d05edbeec54df38885d943dfa27406594c411139690485128525de", size = 42012, upload-time = "2025-07-29T07:42:31.539Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/0865d9765408a7d504f1789944e678f74e0888b96a766d578cb80b040999/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:c3dca4cb5b946ee91b3d6bb700d137b1cd85c20827f89fdf9c16258253489044", size = 39197, upload-time = "2025-07-29T07:42:32.374Z" }, + { url = "https://files.pythonhosted.org/packages/3e/12/76c3207bd186f98b908b6706c2317abb73756d23a4e68ea2bc94825b9015/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e651e17bfde5840e9e4174b01e9e080ce49277b70d424308b36a7969d0d1af73", size = 39840, upload-time = "2025-07-29T07:42:33.227Z" }, + { url = "https://files.pythonhosted.org/packages/5d/0d/574b6cce5555c9f2b31ea189ad44986755eb14e8862db28c8b834b8b64dc/mmh3-5.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:9f64bf06f4bf623325fda3a6d02d36cd69199b9ace99b04bb2d7fd9f89688504", size = 40644, upload-time = "2025-07-29T07:42:34.099Z" }, + { url = "https://files.pythonhosted.org/packages/52/82/3731f8640b79c46707f53ed72034a58baad400be908c87b0088f1f89f986/mmh3-5.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ddc63328889bcaee77b743309e5c7d2d52cee0d7d577837c91b6e7cc9e755e0b", size = 56153, upload-time = "2025-07-29T07:42:35.031Z" }, + { url = "https://files.pythonhosted.org/packages/4f/34/e02dca1d4727fd9fdeaff9e2ad6983e1552804ce1d92cc796e5b052159bb/mmh3-5.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bb0fdc451fb6d86d81ab8f23d881b8d6e37fc373a2deae1c02d27002d2ad7a05", size = 40684, upload-time = "2025-07-29T07:42:35.914Z" }, + { url = "https://files.pythonhosted.org/packages/8f/36/3dee40767356e104967e6ed6d102ba47b0b1ce2a89432239b95a94de1b89/mmh3-5.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b29044e1ffdb84fe164d0a7ea05c7316afea93c00f8ed9449cf357c36fc4f814", size = 40057, upload-time = "2025-07-29T07:42:36.755Z" }, + { url = "https://files.pythonhosted.org/packages/31/58/228c402fccf76eb39a0a01b8fc470fecf21965584e66453b477050ee0e99/mmh3-5.2.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:58981d6ea9646dbbf9e59a30890cbf9f610df0e4a57dbfe09215116fd90b0093", size = 97344, upload-time = "2025-07-29T07:42:37.675Z" }, + { url = "https://files.pythonhosted.org/packages/34/82/fc5ce89006389a6426ef28e326fc065b0fbaaed230373b62d14c889f47ea/mmh3-5.2.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e5634565367b6d98dc4aa2983703526ef556b3688ba3065edb4b9b90ede1c54", size = 103325, upload-time = "2025-07-29T07:42:38.591Z" }, + { url = "https://files.pythonhosted.org/packages/09/8c/261e85777c6aee1ebd53f2f17e210e7481d5b0846cd0b4a5c45f1e3761b8/mmh3-5.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0271ac12415afd3171ab9a3c7cbfc71dee2c68760a7dc9d05bf8ed6ddfa3a7a", size = 106240, upload-time = "2025-07-29T07:42:39.563Z" }, + { url = "https://files.pythonhosted.org/packages/70/73/2f76b3ad8a3d431824e9934403df36c0ddacc7831acf82114bce3c4309c8/mmh3-5.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:45b590e31bc552c6f8e2150ff1ad0c28dd151e9f87589e7eaf508fbdd8e8e908", size = 113060, upload-time = "2025-07-29T07:42:40.585Z" }, + { url = "https://files.pythonhosted.org/packages/9f/b9/7ea61a34e90e50a79a9d87aa1c0b8139a7eaf4125782b34b7d7383472633/mmh3-5.2.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bdde97310d59604f2a9119322f61b31546748499a21b44f6715e8ced9308a6c5", size = 120781, upload-time = "2025-07-29T07:42:41.618Z" }, + { url = "https://files.pythonhosted.org/packages/0f/5b/ae1a717db98c7894a37aeedbd94b3f99e6472a836488f36b6849d003485b/mmh3-5.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc9c5f280438cf1c1a8f9abb87dc8ce9630a964120cfb5dd50d1e7ce79690c7a", size = 99174, upload-time = "2025-07-29T07:42:42.587Z" }, + { url = "https://files.pythonhosted.org/packages/e3/de/000cce1d799fceebb6d4487ae29175dd8e81b48e314cba7b4da90bcf55d7/mmh3-5.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c903e71fd8debb35ad2a4184c1316b3cb22f64ce517b4e6747f25b0a34e41266", size = 98734, upload-time = "2025-07-29T07:42:43.996Z" }, + { url = "https://files.pythonhosted.org/packages/79/19/0dc364391a792b72fbb22becfdeacc5add85cc043cd16986e82152141883/mmh3-5.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:eed4bba7ff8a0d37106ba931ab03bdd3915fbb025bcf4e1f0aa02bc8114960c5", size = 106493, upload-time = "2025-07-29T07:42:45.07Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b1/bc8c28e4d6e807bbb051fefe78e1156d7f104b89948742ad310612ce240d/mmh3-5.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1fdb36b940e9261aff0b5177c5b74a36936b902f473180f6c15bde26143681a9", size = 110089, upload-time = "2025-07-29T07:42:46.122Z" }, + { url = "https://files.pythonhosted.org/packages/3b/a2/d20f3f5c95e9c511806686c70d0a15479cc3941c5f322061697af1c1ff70/mmh3-5.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7303aab41e97adcf010a09efd8f1403e719e59b7705d5e3cfed3dd7571589290", size = 97571, upload-time = "2025-07-29T07:42:47.18Z" }, + { url = "https://files.pythonhosted.org/packages/7b/23/665296fce4f33488deec39a750ffd245cfc07aafb0e3ef37835f91775d14/mmh3-5.2.0-cp313-cp313-win32.whl", hash = "sha256:03e08c6ebaf666ec1e3d6ea657a2d363bb01effd1a9acfe41f9197decaef0051", size = 40806, upload-time = "2025-07-29T07:42:48.166Z" }, + { url = "https://files.pythonhosted.org/packages/59/b0/92e7103f3b20646e255b699e2d0327ce53a3f250e44367a99dc8be0b7c7a/mmh3-5.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:7fddccd4113e7b736706e17a239a696332360cbaddf25ae75b57ba1acce65081", size = 41600, upload-time = "2025-07-29T07:42:49.371Z" }, + { url = "https://files.pythonhosted.org/packages/99/22/0b2bd679a84574647de538c5b07ccaa435dbccc37815067fe15b90fe8dad/mmh3-5.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa0c966ee727aad5406d516375593c5f058c766b21236ab8985693934bb5085b", size = 39349, upload-time = "2025-07-29T07:42:50.268Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ca/a20db059a8a47048aaf550da14a145b56e9c7386fb8280d3ce2962dcebf7/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:e5015f0bb6eb50008bed2d4b1ce0f2a294698a926111e4bb202c0987b4f89078", size = 39209, upload-time = "2025-07-29T07:42:51.559Z" }, + { url = "https://files.pythonhosted.org/packages/98/dd/e5094799d55c7482d814b979a0fd608027d0af1b274bfb4c3ea3e950bfd5/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e0f3ed828d709f5b82d8bfe14f8856120718ec4bd44a5b26102c3030a1e12501", size = 39843, upload-time = "2025-07-29T07:42:52.536Z" }, + { url = "https://files.pythonhosted.org/packages/f4/6b/7844d7f832c85400e7cc89a1348e4e1fdd38c5a38415bb5726bbb8fcdb6c/mmh3-5.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:f35727c5118aba95f0397e18a1a5b8405425581bfe53e821f0fb444cbdc2bc9b", size = 40648, upload-time = "2025-07-29T07:42:53.392Z" }, + { url = "https://files.pythonhosted.org/packages/1f/bf/71f791f48a21ff3190ba5225807cbe4f7223360e96862c376e6e3fb7efa7/mmh3-5.2.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bc244802ccab5220008cb712ca1508cb6a12f0eb64ad62997156410579a1770", size = 56164, upload-time = "2025-07-29T07:42:54.267Z" }, + { url = "https://files.pythonhosted.org/packages/70/1f/f87e3d34d83032b4f3f0f528c6d95a98290fcacf019da61343a49dccfd51/mmh3-5.2.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ff3d50dc3fe8a98059f99b445dfb62792b5d006c5e0b8f03c6de2813b8376110", size = 40692, upload-time = "2025-07-29T07:42:55.234Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e2/db849eaed07117086f3452feca8c839d30d38b830ac59fe1ce65af8be5ad/mmh3-5.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:37a358cc881fe796e099c1db6ce07ff757f088827b4e8467ac52b7a7ffdca647", size = 40068, upload-time = "2025-07-29T07:42:56.158Z" }, + { url = "https://files.pythonhosted.org/packages/df/6b/209af927207af77425b044e32f77f49105a0b05d82ff88af6971d8da4e19/mmh3-5.2.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b9a87025121d1c448f24f27ff53a5fe7b6ef980574b4a4f11acaabe702420d63", size = 97367, upload-time = "2025-07-29T07:42:57.037Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e0/78adf4104c425606a9ce33fb351f790c76a6c2314969c4a517d1ffc92196/mmh3-5.2.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ba55d6ca32eeef8b2625e1e4bfc3b3db52bc63014bd7e5df8cc11bf2b036b12", size = 103306, upload-time = "2025-07-29T07:42:58.522Z" }, + { url = "https://files.pythonhosted.org/packages/a3/79/c2b89f91b962658b890104745b1b6c9ce38d50a889f000b469b91eeb1b9e/mmh3-5.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9ff37ba9f15637e424c2ab57a1a590c52897c845b768e4e0a4958084ec87f22", size = 106312, upload-time = "2025-07-29T07:42:59.552Z" }, + { url = "https://files.pythonhosted.org/packages/4b/14/659d4095528b1a209be90934778c5ffe312177d51e365ddcbca2cac2ec7c/mmh3-5.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a094319ec0db52a04af9fdc391b4d39a1bc72bc8424b47c4411afb05413a44b5", size = 113135, upload-time = "2025-07-29T07:43:00.745Z" }, + { url = "https://files.pythonhosted.org/packages/8d/6f/cd7734a779389a8a467b5c89a48ff476d6f2576e78216a37551a97e9e42a/mmh3-5.2.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5584061fd3da584659b13587f26c6cad25a096246a481636d64375d0c1f6c07", size = 120775, upload-time = "2025-07-29T07:43:02.124Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ca/8256e3b96944408940de3f9291d7e38a283b5761fe9614d4808fcf27bd62/mmh3-5.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecbfc0437ddfdced5e7822d1ce4855c9c64f46819d0fdc4482c53f56c707b935", size = 99178, upload-time = "2025-07-29T07:43:03.182Z" }, + { url = "https://files.pythonhosted.org/packages/8a/32/39e2b3cf06b6e2eb042c984dab8680841ac2a0d3ca6e0bea30db1f27b565/mmh3-5.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7b986d506a8e8ea345791897ba5d8ba0d9d8820cd4fc3e52dbe6de19388de2e7", size = 98738, upload-time = "2025-07-29T07:43:04.207Z" }, + { url = "https://files.pythonhosted.org/packages/61/d3/7bbc8e0e8cf65ebbe1b893ffa0467b7ecd1bd07c3bbf6c9db4308ada22ec/mmh3-5.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:38d899a156549da8ef6a9f1d6f7ef231228d29f8f69bce2ee12f5fba6d6fd7c5", size = 106510, upload-time = "2025-07-29T07:43:05.656Z" }, + { url = "https://files.pythonhosted.org/packages/10/99/b97e53724b52374e2f3859046f0eb2425192da356cb19784d64bc17bb1cf/mmh3-5.2.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d86651fa45799530885ba4dab3d21144486ed15285e8784181a0ab37a4552384", size = 110053, upload-time = "2025-07-29T07:43:07.204Z" }, + { url = "https://files.pythonhosted.org/packages/ac/62/3688c7d975ed195155671df68788c83fed6f7909b6ec4951724c6860cb97/mmh3-5.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c463d7c1c4cfc9d751efeaadd936bbba07b5b0ed81a012b3a9f5a12f0872bd6e", size = 97546, upload-time = "2025-07-29T07:43:08.226Z" }, + { url = "https://files.pythonhosted.org/packages/ca/3b/c6153250f03f71a8b7634cded82939546cdfba02e32f124ff51d52c6f991/mmh3-5.2.0-cp314-cp314-win32.whl", hash = "sha256:bb4fe46bdc6104fbc28db7a6bacb115ee6368ff993366bbd8a2a7f0076e6f0c0", size = 41422, upload-time = "2025-07-29T07:43:09.216Z" }, + { url = "https://files.pythonhosted.org/packages/74/01/a27d98bab083a435c4c07e9d1d720d4c8a578bf4c270bae373760b1022be/mmh3-5.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c7f0b342fd06044bedd0b6e72177ddc0076f54fd89ee239447f8b271d919d9b", size = 42135, upload-time = "2025-07-29T07:43:10.183Z" }, + { url = "https://files.pythonhosted.org/packages/cb/c9/dbba5507e95429b8b380e2ba091eff5c20a70a59560934dff0ad8392b8c8/mmh3-5.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:3193752fc05ea72366c2b63ff24b9a190f422e32d75fdeae71087c08fff26115", size = 39879, upload-time = "2025-07-29T07:43:11.106Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d1/c8c0ef839c17258b9de41b84f663574fabcf8ac2007b7416575e0f65ff6e/mmh3-5.2.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:69fc339d7202bea69ef9bd7c39bfdf9fdabc8e6822a01eba62fb43233c1b3932", size = 57696, upload-time = "2025-07-29T07:43:11.989Z" }, + { url = "https://files.pythonhosted.org/packages/2f/55/95e2b9ff201e89f9fe37036037ab61a6c941942b25cdb7b6a9df9b931993/mmh3-5.2.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:12da42c0a55c9d86ab566395324213c319c73ecb0c239fad4726324212b9441c", size = 41421, upload-time = "2025-07-29T07:43:13.269Z" }, + { url = "https://files.pythonhosted.org/packages/77/79/9be23ad0b7001a4b22752e7693be232428ecc0a35068a4ff5c2f14ef8b20/mmh3-5.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f7f9034c7cf05ddfaac8d7a2e63a3c97a840d4615d0a0e65ba8bdf6f8576e3be", size = 40853, upload-time = "2025-07-29T07:43:14.888Z" }, + { url = "https://files.pythonhosted.org/packages/ac/1b/96b32058eda1c1dee8264900c37c359a7325c1f11f5ff14fd2be8e24eff9/mmh3-5.2.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11730eeb16dfcf9674fdea9bb6b8e6dd9b40813b7eb839bc35113649eef38aeb", size = 109694, upload-time = "2025-07-29T07:43:15.816Z" }, + { url = "https://files.pythonhosted.org/packages/8d/6f/a2ae44cd7dad697b6dea48390cbc977b1e5ca58fda09628cbcb2275af064/mmh3-5.2.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:932a6eec1d2e2c3c9e630d10f7128d80e70e2d47fe6b8c7ea5e1afbd98733e65", size = 117438, upload-time = "2025-07-29T07:43:16.865Z" }, + { url = "https://files.pythonhosted.org/packages/a0/08/bfb75451c83f05224a28afeaf3950c7b793c0b71440d571f8e819cfb149a/mmh3-5.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca975c51c5028947bbcfc24966517aac06a01d6c921e30f7c5383c195f87991", size = 120409, upload-time = "2025-07-29T07:43:18.207Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ea/8b118b69b2ff8df568f742387d1a159bc654a0f78741b31437dd047ea28e/mmh3-5.2.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5b0b58215befe0f0e120b828f7645e97719bbba9f23b69e268ed0ac7adde8645", size = 125909, upload-time = "2025-07-29T07:43:19.39Z" }, + { url = "https://files.pythonhosted.org/packages/3e/11/168cc0b6a30650032e351a3b89b8a47382da541993a03af91e1ba2501234/mmh3-5.2.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29c2b9ce61886809d0492a274a5a53047742dea0f703f9c4d5d223c3ea6377d3", size = 135331, upload-time = "2025-07-29T07:43:20.435Z" }, + { url = "https://files.pythonhosted.org/packages/31/05/e3a9849b1c18a7934c64e831492c99e67daebe84a8c2f2c39a7096a830e3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a367d4741ac0103f8198c82f429bccb9359f543ca542b06a51f4f0332e8de279", size = 110085, upload-time = "2025-07-29T07:43:21.92Z" }, + { url = "https://files.pythonhosted.org/packages/d9/d5/a96bcc306e3404601418b2a9a370baec92af84204528ba659fdfe34c242f/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5a5dba98e514fb26241868f6eb90a7f7ca0e039aed779342965ce24ea32ba513", size = 111195, upload-time = "2025-07-29T07:43:23.066Z" }, + { url = "https://files.pythonhosted.org/packages/af/29/0fd49801fec5bff37198684e0849b58e0dab3a2a68382a357cfffb0fafc3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:941603bfd75a46023807511c1ac2f1b0f39cccc393c15039969806063b27e6db", size = 116919, upload-time = "2025-07-29T07:43:24.178Z" }, + { url = "https://files.pythonhosted.org/packages/2d/04/4f3c32b0a2ed762edca45d8b46568fc3668e34f00fb1e0a3b5451ec1281c/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:132dd943451a7c7546978863d2f5a64977928410782e1a87d583cb60eb89e667", size = 123160, upload-time = "2025-07-29T07:43:25.26Z" }, + { url = "https://files.pythonhosted.org/packages/91/76/3d29eaa38821730633d6a240d36fa8ad2807e9dfd432c12e1a472ed211eb/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f698733a8a494466432d611a8f0d1e026f5286dee051beea4b3c3146817e35d5", size = 110206, upload-time = "2025-07-29T07:43:26.699Z" }, + { url = "https://files.pythonhosted.org/packages/44/1c/ccf35892684d3a408202e296e56843743e0b4fb1629e59432ea88cdb3909/mmh3-5.2.0-cp314-cp314t-win32.whl", hash = "sha256:6d541038b3fc360ec538fc116de87462627944765a6750308118f8b509a8eec7", size = 41970, upload-time = "2025-07-29T07:43:27.666Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/b9e4f1e5adb5e21eb104588fcee2cd1eaa8308255173481427d5ecc4284e/mmh3-5.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e912b19cf2378f2967d0c08e86ff4c6c360129887f678e27e4dde970d21b3f4d", size = 43063, upload-time = "2025-07-29T07:43:28.582Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/0e61d9a4e29c8679356795a40e48f647b4aad58d71bfc969f0f8f56fb912/mmh3-5.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e7884931fe5e788163e7b3c511614130c2c59feffdc21112290a194487efb2e9", size = 40455, upload-time = "2025-07-29T07:43:29.563Z" }, +] + +[[package]] +name = "more-itertools" +version = "10.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, +] + +[[package]] +name = "msgspec" +version = "0.19.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/9b/95d8ce458462b8b71b8a70fa94563b2498b89933689f3a7b8911edfae3d7/msgspec-0.19.0.tar.gz", hash = "sha256:604037e7cd475345848116e89c553aa9a233259733ab51986ac924ab1b976f8e", size = 216934, upload-time = "2024-12-27T17:40:28.597Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/5f/a70c24f075e3e7af2fae5414c7048b0e11389685b7f717bb55ba282a34a7/msgspec-0.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f98bd8962ad549c27d63845b50af3f53ec468b6318400c9f1adfe8b092d7b62f", size = 190485, upload-time = "2024-12-27T17:39:44.974Z" }, + { url = "https://files.pythonhosted.org/packages/89/b0/1b9763938cfae12acf14b682fcf05c92855974d921a5a985ecc197d1c672/msgspec-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:43bbb237feab761b815ed9df43b266114203f53596f9b6e6f00ebd79d178cdf2", size = 183910, upload-time = "2024-12-27T17:39:46.401Z" }, + { url = "https://files.pythonhosted.org/packages/87/81/0c8c93f0b92c97e326b279795f9c5b956c5a97af28ca0fbb9fd86c83737a/msgspec-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cfc033c02c3e0aec52b71710d7f84cb3ca5eb407ab2ad23d75631153fdb1f12", size = 210633, upload-time = "2024-12-27T17:39:49.099Z" }, + { url = "https://files.pythonhosted.org/packages/d0/ef/c5422ce8af73928d194a6606f8ae36e93a52fd5e8df5abd366903a5ca8da/msgspec-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d911c442571605e17658ca2b416fd8579c5050ac9adc5e00c2cb3126c97f73bc", size = 213594, upload-time = "2024-12-27T17:39:51.204Z" }, + { url = "https://files.pythonhosted.org/packages/19/2b/4137bc2ed45660444842d042be2cf5b18aa06efd2cda107cff18253b9653/msgspec-0.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:757b501fa57e24896cf40a831442b19a864f56d253679f34f260dcb002524a6c", size = 214053, upload-time = "2024-12-27T17:39:52.866Z" }, + { url = "https://files.pythonhosted.org/packages/9d/e6/8ad51bdc806aac1dc501e8fe43f759f9ed7284043d722b53323ea421c360/msgspec-0.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5f0f65f29b45e2816d8bded36e6b837a4bf5fb60ec4bc3c625fa2c6da4124537", size = 219081, upload-time = "2024-12-27T17:39:55.142Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ef/27dd35a7049c9a4f4211c6cd6a8c9db0a50647546f003a5867827ec45391/msgspec-0.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:067f0de1c33cfa0b6a8206562efdf6be5985b988b53dd244a8e06f993f27c8c0", size = 187467, upload-time = "2024-12-27T17:39:56.531Z" }, + { url = "https://files.pythonhosted.org/packages/3c/cb/2842c312bbe618d8fefc8b9cedce37f773cdc8fa453306546dba2c21fd98/msgspec-0.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f12d30dd6266557aaaf0aa0f9580a9a8fbeadfa83699c487713e355ec5f0bd86", size = 190498, upload-time = "2024-12-27T17:40:00.427Z" }, + { url = "https://files.pythonhosted.org/packages/58/95/c40b01b93465e1a5f3b6c7d91b10fb574818163740cc3acbe722d1e0e7e4/msgspec-0.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82b2c42c1b9ebc89e822e7e13bbe9d17ede0c23c187469fdd9505afd5a481314", size = 183950, upload-time = "2024-12-27T17:40:04.219Z" }, + { url = "https://files.pythonhosted.org/packages/e8/f0/5b764e066ce9aba4b70d1db8b087ea66098c7c27d59b9dd8a3532774d48f/msgspec-0.19.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19746b50be214a54239aab822964f2ac81e38b0055cca94808359d779338c10e", size = 210647, upload-time = "2024-12-27T17:40:05.606Z" }, + { url = "https://files.pythonhosted.org/packages/9d/87/bc14f49bc95c4cb0dd0a8c56028a67c014ee7e6818ccdce74a4862af259b/msgspec-0.19.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60ef4bdb0ec8e4ad62e5a1f95230c08efb1f64f32e6e8dd2ced685bcc73858b5", size = 213563, upload-time = "2024-12-27T17:40:10.516Z" }, + { url = "https://files.pythonhosted.org/packages/53/2f/2b1c2b056894fbaa975f68f81e3014bb447516a8b010f1bed3fb0e016ed7/msgspec-0.19.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac7f7c377c122b649f7545810c6cd1b47586e3aa3059126ce3516ac7ccc6a6a9", size = 213996, upload-time = "2024-12-27T17:40:12.244Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5a/4cd408d90d1417e8d2ce6a22b98a6853c1b4d7cb7669153e4424d60087f6/msgspec-0.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5bc1472223a643f5ffb5bf46ccdede7f9795078194f14edd69e3aab7020d327", size = 219087, upload-time = "2024-12-27T17:40:14.881Z" }, + { url = "https://files.pythonhosted.org/packages/23/d8/f15b40611c2d5753d1abb0ca0da0c75348daf1252220e5dda2867bd81062/msgspec-0.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:317050bc0f7739cb30d257ff09152ca309bf5a369854bbf1e57dffc310c1f20f", size = 187432, upload-time = "2024-12-27T17:40:16.256Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +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 = "narwhals" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/87/76/9ca8f4d03f02b8289807d0c91eeb01fa6b7fdd6273769d5bd1f94773b40b/narwhals-2.7.0.tar.gz", hash = "sha256:e3fff7f1610fd3318ede78c969bc5954ce710d585eefdb689586fb69da3da43c", size = 569315, upload-time = "2025-10-06T09:39:37.69Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/0d/bc630dfd34ad2150d40f9392e94d3803980e71a47e10a709ce9bfcd40ffe/narwhals-2.7.0-py3-none-any.whl", hash = "sha256:010791aa0cee86d90bf2b658264aaec3eeea34fb4ddf2e83746ea4940bcffae3", size = 412767, upload-time = "2025-10-06T09:39:35.564Z" }, +] + +[[package]] +name = "numpy" +version = "2.3.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/19/95b3d357407220ed24c139018d2518fab0a61a948e68286a25f1a4d049ff/numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029", size = 20576648, upload-time = "2025-09-09T16:54:12.543Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/5d/bb7fc075b762c96329147799e1bcc9176ab07ca6375ea976c475482ad5b3/numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf", size = 20957014, upload-time = "2025-09-09T15:56:29.966Z" }, + { url = "https://files.pythonhosted.org/packages/6b/0e/c6211bb92af26517acd52125a237a92afe9c3124c6a68d3b9f81b62a0568/numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25", size = 14185220, upload-time = "2025-09-09T15:56:32.175Z" }, + { url = "https://files.pythonhosted.org/packages/22/f2/07bb754eb2ede9073f4054f7c0286b0d9d2e23982e090a80d478b26d35ca/numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe", size = 5113918, upload-time = "2025-09-09T15:56:34.175Z" }, + { url = "https://files.pythonhosted.org/packages/81/0a/afa51697e9fb74642f231ea36aca80fa17c8fb89f7a82abd5174023c3960/numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b", size = 6647922, upload-time = "2025-09-09T15:56:36.149Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f5/122d9cdb3f51c520d150fef6e87df9279e33d19a9611a87c0d2cf78a89f4/numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8", size = 14281991, upload-time = "2025-09-09T15:56:40.548Z" }, + { url = "https://files.pythonhosted.org/packages/51/64/7de3c91e821a2debf77c92962ea3fe6ac2bc45d0778c1cbe15d4fce2fd94/numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20", size = 16641643, upload-time = "2025-09-09T15:56:43.343Z" }, + { url = "https://files.pythonhosted.org/packages/30/e4/961a5fa681502cd0d68907818b69f67542695b74e3ceaa513918103b7e80/numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea", size = 16056787, upload-time = "2025-09-09T15:56:46.141Z" }, + { url = "https://files.pythonhosted.org/packages/99/26/92c912b966e47fbbdf2ad556cb17e3a3088e2e1292b9833be1dfa5361a1a/numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7", size = 18579598, upload-time = "2025-09-09T15:56:49.844Z" }, + { url = "https://files.pythonhosted.org/packages/17/b6/fc8f82cb3520768718834f310c37d96380d9dc61bfdaf05fe5c0b7653e01/numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf", size = 6320800, upload-time = "2025-09-09T15:56:52.499Z" }, + { url = "https://files.pythonhosted.org/packages/32/ee/de999f2625b80d043d6d2d628c07d0d5555a677a3cf78fdf868d409b8766/numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb", size = 12786615, upload-time = "2025-09-09T15:56:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/49/6e/b479032f8a43559c383acb20816644f5f91c88f633d9271ee84f3b3a996c/numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5", size = 10195936, upload-time = "2025-09-09T15:56:56.541Z" }, + { url = "https://files.pythonhosted.org/packages/7d/b9/984c2b1ee61a8b803bf63582b4ac4242cf76e2dbd663efeafcb620cc0ccb/numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf", size = 20949588, upload-time = "2025-09-09T15:56:59.087Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e4/07970e3bed0b1384d22af1e9912527ecbeb47d3b26e9b6a3bced068b3bea/numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7", size = 14177802, upload-time = "2025-09-09T15:57:01.73Z" }, + { url = "https://files.pythonhosted.org/packages/35/c7/477a83887f9de61f1203bad89cf208b7c19cc9fef0cebef65d5a1a0619f2/numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6", size = 5106537, upload-time = "2025-09-09T15:57:03.765Z" }, + { url = "https://files.pythonhosted.org/packages/52/47/93b953bd5866a6f6986344d045a207d3f1cfbad99db29f534ea9cee5108c/numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7", size = 6640743, upload-time = "2025-09-09T15:57:07.921Z" }, + { url = "https://files.pythonhosted.org/packages/23/83/377f84aaeb800b64c0ef4de58b08769e782edcefa4fea712910b6f0afd3c/numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c", size = 14278881, upload-time = "2025-09-09T15:57:11.349Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a5/bf3db6e66c4b160d6ea10b534c381a1955dfab34cb1017ea93aa33c70ed3/numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93", size = 16636301, upload-time = "2025-09-09T15:57:14.245Z" }, + { url = "https://files.pythonhosted.org/packages/a2/59/1287924242eb4fa3f9b3a2c30400f2e17eb2707020d1c5e3086fe7330717/numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae", size = 16053645, upload-time = "2025-09-09T15:57:16.534Z" }, + { url = "https://files.pythonhosted.org/packages/e6/93/b3d47ed882027c35e94ac2320c37e452a549f582a5e801f2d34b56973c97/numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86", size = 18578179, upload-time = "2025-09-09T15:57:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/20/d9/487a2bccbf7cc9d4bfc5f0f197761a5ef27ba870f1e3bbb9afc4bbe3fcc2/numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8", size = 6312250, upload-time = "2025-09-09T15:57:21.296Z" }, + { url = "https://files.pythonhosted.org/packages/1b/b5/263ebbbbcede85028f30047eab3d58028d7ebe389d6493fc95ae66c636ab/numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf", size = 12783269, upload-time = "2025-09-09T15:57:23.034Z" }, + { url = "https://files.pythonhosted.org/packages/fa/75/67b8ca554bbeaaeb3fac2e8bce46967a5a06544c9108ec0cf5cece559b6c/numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5", size = 10195314, upload-time = "2025-09-09T15:57:25.045Z" }, + { url = "https://files.pythonhosted.org/packages/11/d0/0d1ddec56b162042ddfafeeb293bac672de9b0cfd688383590090963720a/numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc", size = 21048025, upload-time = "2025-09-09T15:57:27.257Z" }, + { url = "https://files.pythonhosted.org/packages/36/9e/1996ca6b6d00415b6acbdd3c42f7f03ea256e2c3f158f80bd7436a8a19f3/numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc", size = 14301053, upload-time = "2025-09-09T15:57:30.077Z" }, + { url = "https://files.pythonhosted.org/packages/05/24/43da09aa764c68694b76e84b3d3f0c44cb7c18cdc1ba80e48b0ac1d2cd39/numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b", size = 5229444, upload-time = "2025-09-09T15:57:32.733Z" }, + { url = "https://files.pythonhosted.org/packages/bc/14/50ffb0f22f7218ef8af28dd089f79f68289a7a05a208db9a2c5dcbe123c1/numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19", size = 6738039, upload-time = "2025-09-09T15:57:34.328Z" }, + { url = "https://files.pythonhosted.org/packages/55/52/af46ac0795e09657d45a7f4db961917314377edecf66db0e39fa7ab5c3d3/numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30", size = 14352314, upload-time = "2025-09-09T15:57:36.255Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b1/dc226b4c90eb9f07a3fff95c2f0db3268e2e54e5cce97c4ac91518aee71b/numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e", size = 16701722, upload-time = "2025-09-09T15:57:38.622Z" }, + { url = "https://files.pythonhosted.org/packages/9d/9d/9d8d358f2eb5eced14dba99f110d83b5cd9a4460895230f3b396ad19a323/numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3", size = 16132755, upload-time = "2025-09-09T15:57:41.16Z" }, + { url = "https://files.pythonhosted.org/packages/b6/27/b3922660c45513f9377b3fb42240bec63f203c71416093476ec9aa0719dc/numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea", size = 18651560, upload-time = "2025-09-09T15:57:43.459Z" }, + { url = "https://files.pythonhosted.org/packages/5b/8e/3ab61a730bdbbc201bb245a71102aa609f0008b9ed15255500a99cd7f780/numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd", size = 6442776, upload-time = "2025-09-09T15:57:45.793Z" }, + { url = "https://files.pythonhosted.org/packages/1c/3a/e22b766b11f6030dc2decdeff5c2fb1610768055603f9f3be88b6d192fb2/numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d", size = 12927281, upload-time = "2025-09-09T15:57:47.492Z" }, + { url = "https://files.pythonhosted.org/packages/7b/42/c2e2bc48c5e9b2a83423f99733950fbefd86f165b468a3d85d52b30bf782/numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1", size = 10265275, upload-time = "2025-09-09T15:57:49.647Z" }, + { url = "https://files.pythonhosted.org/packages/6b/01/342ad585ad82419b99bcf7cebe99e61da6bedb89e213c5fd71acc467faee/numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593", size = 20951527, upload-time = "2025-09-09T15:57:52.006Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d8/204e0d73fc1b7a9ee80ab1fe1983dd33a4d64a4e30a05364b0208e9a241a/numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652", size = 14186159, upload-time = "2025-09-09T15:57:54.407Z" }, + { url = "https://files.pythonhosted.org/packages/22/af/f11c916d08f3a18fb8ba81ab72b5b74a6e42ead4c2846d270eb19845bf74/numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7", size = 5114624, upload-time = "2025-09-09T15:57:56.5Z" }, + { url = "https://files.pythonhosted.org/packages/fb/11/0ed919c8381ac9d2ffacd63fd1f0c34d27e99cab650f0eb6f110e6ae4858/numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a", size = 6642627, upload-time = "2025-09-09T15:57:58.206Z" }, + { url = "https://files.pythonhosted.org/packages/ee/83/deb5f77cb0f7ba6cb52b91ed388b47f8f3c2e9930d4665c600408d9b90b9/numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe", size = 14296926, upload-time = "2025-09-09T15:58:00.035Z" }, + { url = "https://files.pythonhosted.org/packages/77/cc/70e59dcb84f2b005d4f306310ff0a892518cc0c8000a33d0e6faf7ca8d80/numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421", size = 16638958, upload-time = "2025-09-09T15:58:02.738Z" }, + { url = "https://files.pythonhosted.org/packages/b6/5a/b2ab6c18b4257e099587d5b7f903317bd7115333ad8d4ec4874278eafa61/numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021", size = 16071920, upload-time = "2025-09-09T15:58:05.029Z" }, + { url = "https://files.pythonhosted.org/packages/b8/f1/8b3fdc44324a259298520dd82147ff648979bed085feeacc1250ef1656c0/numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf", size = 18577076, upload-time = "2025-09-09T15:58:07.745Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a1/b87a284fb15a42e9274e7fcea0dad259d12ddbf07c1595b26883151ca3b4/numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0", size = 6366952, upload-time = "2025-09-09T15:58:10.096Z" }, + { url = "https://files.pythonhosted.org/packages/70/5f/1816f4d08f3b8f66576d8433a66f8fa35a5acfb3bbd0bf6c31183b003f3d/numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8", size = 12919322, upload-time = "2025-09-09T15:58:12.138Z" }, + { url = "https://files.pythonhosted.org/packages/8c/de/072420342e46a8ea41c324a555fa90fcc11637583fb8df722936aed1736d/numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe", size = 10478630, upload-time = "2025-09-09T15:58:14.64Z" }, + { url = "https://files.pythonhosted.org/packages/d5/df/ee2f1c0a9de7347f14da5dd3cd3c3b034d1b8607ccb6883d7dd5c035d631/numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00", size = 21047987, upload-time = "2025-09-09T15:58:16.889Z" }, + { url = "https://files.pythonhosted.org/packages/d6/92/9453bdc5a4e9e69cf4358463f25e8260e2ffc126d52e10038b9077815989/numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a", size = 14301076, upload-time = "2025-09-09T15:58:20.343Z" }, + { url = "https://files.pythonhosted.org/packages/13/77/1447b9eb500f028bb44253105bd67534af60499588a5149a94f18f2ca917/numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d", size = 5229491, upload-time = "2025-09-09T15:58:22.481Z" }, + { url = "https://files.pythonhosted.org/packages/3d/f9/d72221b6ca205f9736cb4b2ce3b002f6e45cd67cd6a6d1c8af11a2f0b649/numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a", size = 6737913, upload-time = "2025-09-09T15:58:24.569Z" }, + { url = "https://files.pythonhosted.org/packages/3c/5f/d12834711962ad9c46af72f79bb31e73e416ee49d17f4c797f72c96b6ca5/numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54", size = 14352811, upload-time = "2025-09-09T15:58:26.416Z" }, + { url = "https://files.pythonhosted.org/packages/a1/0d/fdbec6629d97fd1bebed56cd742884e4eead593611bbe1abc3eb40d304b2/numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e", size = 16702689, upload-time = "2025-09-09T15:58:28.831Z" }, + { url = "https://files.pythonhosted.org/packages/9b/09/0a35196dc5575adde1eb97ddfbc3e1687a814f905377621d18ca9bc2b7dd/numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097", size = 16133855, upload-time = "2025-09-09T15:58:31.349Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ca/c9de3ea397d576f1b6753eaa906d4cdef1bf97589a6d9825a349b4729cc2/numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970", size = 18652520, upload-time = "2025-09-09T15:58:33.762Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c2/e5ed830e08cd0196351db55db82f65bc0ab05da6ef2b72a836dcf1936d2f/numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5", size = 6515371, upload-time = "2025-09-09T15:58:36.04Z" }, + { url = "https://files.pythonhosted.org/packages/47/c7/b0f6b5b67f6788a0725f744496badbb604d226bf233ba716683ebb47b570/numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f", size = 13112576, upload-time = "2025-09-09T15:58:37.927Z" }, + { url = "https://files.pythonhosted.org/packages/06/b9/33bba5ff6fb679aa0b1f8a07e853f002a6b04b9394db3069a1270a7784ca/numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b", size = 10545953, upload-time = "2025-09-09T15:58:40.576Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pandas" +version = "2.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "tzdata" }, +] +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/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 = "parso" +version = "0.8.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "prometheus-client" +version = "0.24.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/58/a794d23feb6b00fc0c72787d7e87d872a6730dd9ed7c7b3e954637d8f280/prometheus_client-0.24.1.tar.gz", hash = "sha256:7e0ced7fbbd40f7b84962d5d2ab6f17ef88a72504dcf7c0b40737b43b2a461f9", size = 85616, upload-time = "2026-01-14T15:26:26.965Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl", hash = "sha256:150db128af71a5c2482b36e588fc8a6b95e498750da4b17065947c16070f4055", size = 64057, upload-time = "2026-01-14T15:26:24.42Z" }, +] + +[[package]] +name = "proto-plus" +version = "1.26.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/ac/87285f15f7cce6d4a008f33f1757fb5a13611ea8914eb58c3d0d26243468/proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012", size = 56142, upload-time = "2025-03-10T15:54:38.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163, upload-time = "2025-03-10T15:54:37.335Z" }, +] + +[[package]] +name = "protobuf" +version = "6.32.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/a4/cc17347aa2897568beece2e674674359f911d6fe21b0b8d6268cd42727ac/protobuf-6.32.1.tar.gz", hash = "sha256:ee2469e4a021474ab9baafea6cd070e5bf27c7d29433504ddea1a4ee5850f68d", size = 440635, upload-time = "2025-09-11T21:38:42.935Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/98/645183ea03ab3995d29086b8bf4f7562ebd3d10c9a4b14ee3f20d47cfe50/protobuf-6.32.1-cp310-abi3-win32.whl", hash = "sha256:a8a32a84bc9f2aad712041b8b366190f71dde248926da517bde9e832e4412085", size = 424411, upload-time = "2025-09-11T21:38:27.427Z" }, + { url = "https://files.pythonhosted.org/packages/8c/f3/6f58f841f6ebafe076cebeae33fc336e900619d34b1c93e4b5c97a81fdfa/protobuf-6.32.1-cp310-abi3-win_amd64.whl", hash = "sha256:b00a7d8c25fa471f16bc8153d0e53d6c9e827f0953f3c09aaa4331c718cae5e1", size = 435738, upload-time = "2025-09-11T21:38:30.959Z" }, + { url = "https://files.pythonhosted.org/packages/10/56/a8a3f4e7190837139e68c7002ec749190a163af3e330f65d90309145a210/protobuf-6.32.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d8c7e6eb619ffdf105ee4ab76af5a68b60a9d0f66da3ea12d1640e6d8dab7281", size = 426454, upload-time = "2025-09-11T21:38:34.076Z" }, + { url = "https://files.pythonhosted.org/packages/3f/be/8dd0a927c559b37d7a6c8ab79034fd167dcc1f851595f2e641ad62be8643/protobuf-6.32.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:2f5b80a49e1eb7b86d85fcd23fe92df154b9730a725c3b38c4e43b9d77018bf4", size = 322874, upload-time = "2025-09-11T21:38:35.509Z" }, + { url = "https://files.pythonhosted.org/packages/5c/f6/88d77011b605ef979aace37b7703e4eefad066f7e84d935e5a696515c2dd/protobuf-6.32.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:b1864818300c297265c83a4982fd3169f97122c299f56a56e2445c3698d34710", size = 322013, upload-time = "2025-09-11T21:38:37.017Z" }, + { url = "https://files.pythonhosted.org/packages/97/b7/15cc7d93443d6c6a84626ae3258a91f4c6ac8c0edd5df35ea7658f71b79c/protobuf-6.32.1-py3-none-any.whl", hash = "sha256:2601b779fc7d32a866c6b4404f9d42a3f67c5b9f3f15b4db3cccabe06b95c346", size = 169289, upload-time = "2025-09-11T21:38:41.234Z" }, +] + +[[package]] +name = "psutil" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/31/4723d756b59344b643542936e37a31d1d3204bcdc42a7daa8ee9eb06fb50/psutil-7.1.0.tar.gz", hash = "sha256:655708b3c069387c8b77b072fc429a57d0e214221d01c0a772df7dfedcb3bcd2", size = 497660, upload-time = "2025-09-17T20:14:52.902Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/62/ce4051019ee20ce0ed74432dd73a5bb087a6704284a470bb8adff69a0932/psutil-7.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76168cef4397494250e9f4e73eb3752b146de1dd950040b29186d0cce1d5ca13", size = 245242, upload-time = "2025-09-17T20:14:56.126Z" }, + { url = "https://files.pythonhosted.org/packages/38/61/f76959fba841bf5b61123fbf4b650886dc4094c6858008b5bf73d9057216/psutil-7.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:5d007560c8c372efdff9e4579c2846d71de737e4605f611437255e81efcca2c5", size = 246682, upload-time = "2025-09-17T20:14:58.25Z" }, + { url = "https://files.pythonhosted.org/packages/88/7a/37c99d2e77ec30d63398ffa6a660450b8a62517cabe44b3e9bae97696e8d/psutil-7.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22e4454970b32472ce7deaa45d045b34d3648ce478e26a04c7e858a0a6e75ff3", size = 287994, upload-time = "2025-09-17T20:14:59.901Z" }, + { url = "https://files.pythonhosted.org/packages/9d/de/04c8c61232f7244aa0a4b9a9fbd63a89d5aeaf94b2fc9d1d16e2faa5cbb0/psutil-7.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c70e113920d51e89f212dd7be06219a9b88014e63a4cec69b684c327bc474e3", size = 291163, upload-time = "2025-09-17T20:15:01.481Z" }, + { url = "https://files.pythonhosted.org/packages/f4/58/c4f976234bf6d4737bc8c02a81192f045c307b72cf39c9e5c5a2d78927f6/psutil-7.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d4a113425c037300de3ac8b331637293da9be9713855c4fc9d2d97436d7259d", size = 293625, upload-time = "2025-09-17T20:15:04.492Z" }, + { url = "https://files.pythonhosted.org/packages/79/87/157c8e7959ec39ced1b11cc93c730c4fb7f9d408569a6c59dbd92ceb35db/psutil-7.1.0-cp37-abi3-win32.whl", hash = "sha256:09ad740870c8d219ed8daae0ad3b726d3bf9a028a198e7f3080f6a1888b99bca", size = 244812, upload-time = "2025-09-17T20:15:07.462Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e9/b44c4f697276a7a95b8e94d0e320a7bf7f3318521b23de69035540b39838/psutil-7.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:57f5e987c36d3146c0dd2528cd42151cf96cd359b9d67cfff836995cc5df9a3d", size = 247965, upload-time = "2025-09-17T20:15:09.673Z" }, + { url = "https://files.pythonhosted.org/packages/26/65/1070a6e3c036f39142c2820c4b52e9243246fcfc3f96239ac84472ba361e/psutil-7.1.0-cp37-abi3-win_arm64.whl", hash = "sha256:6937cb68133e7c97b6cc9649a570c9a18ba0efebed46d8c5dae4c07fa1b67a07", size = 244971, upload-time = "2025-09-17T20:15:12.262Z" }, +] + +[[package]] +name = "psycopg2-binary" +version = "2.9.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cb/0e/bdc8274dc0585090b4e3432267d7be4dfbfd8971c0fa59167c711105a6bf/psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2", size = 385764, upload-time = "2024-10-16T11:24:58.126Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/7d/465cc9795cf76f6d329efdafca74693714556ea3891813701ac1fee87545/psycopg2_binary-2.9.10-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:880845dfe1f85d9d5f7c412efea7a08946a46894537e4e5d091732eb1d34d9a0", size = 3044771, upload-time = "2024-10-16T11:20:35.234Z" }, + { url = "https://files.pythonhosted.org/packages/8b/31/6d225b7b641a1a2148e3ed65e1aa74fc86ba3fee850545e27be9e1de893d/psycopg2_binary-2.9.10-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9440fa522a79356aaa482aa4ba500b65f28e5d0e63b801abf6aa152a29bd842a", size = 3275336, upload-time = "2024-10-16T11:20:38.742Z" }, + { url = "https://files.pythonhosted.org/packages/30/b7/a68c2b4bff1cbb1728e3ec864b2d92327c77ad52edcd27922535a8366f68/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3923c1d9870c49a2d44f795df0c889a22380d36ef92440ff618ec315757e539", size = 2851637, upload-time = "2024-10-16T11:20:42.145Z" }, + { url = "https://files.pythonhosted.org/packages/0b/b1/cfedc0e0e6f9ad61f8657fd173b2f831ce261c02a08c0b09c652b127d813/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b2c956c028ea5de47ff3a8d6b3cc3330ab45cf0b7c3da35a2d6ff8420896526", size = 3082097, upload-time = "2024-10-16T11:20:46.185Z" }, + { url = "https://files.pythonhosted.org/packages/18/ed/0a8e4153c9b769f59c02fb5e7914f20f0b2483a19dae7bf2db54b743d0d0/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f758ed67cab30b9a8d2833609513ce4d3bd027641673d4ebc9c067e4d208eec1", size = 3264776, upload-time = "2024-10-16T11:20:50.879Z" }, + { url = "https://files.pythonhosted.org/packages/10/db/d09da68c6a0cdab41566b74e0a6068a425f077169bed0946559b7348ebe9/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cd9b4f2cfab88ed4a9106192de509464b75a906462fb846b936eabe45c2063e", size = 3020968, upload-time = "2024-10-16T11:20:56.819Z" }, + { url = "https://files.pythonhosted.org/packages/94/28/4d6f8c255f0dfffb410db2b3f9ac5218d959a66c715c34cac31081e19b95/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dc08420625b5a20b53551c50deae6e231e6371194fa0651dbe0fb206452ae1f", size = 2872334, upload-time = "2024-10-16T11:21:02.411Z" }, + { url = "https://files.pythonhosted.org/packages/05/f7/20d7bf796593c4fea95e12119d6cc384ff1f6141a24fbb7df5a668d29d29/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7cd730dfa7c36dbe8724426bf5612798734bff2d3c3857f36f2733f5bfc7c00", size = 2822722, upload-time = "2024-10-16T11:21:09.01Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e4/0c407ae919ef626dbdb32835a03b6737013c3cc7240169843965cada2bdf/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:155e69561d54d02b3c3209545fb08938e27889ff5a10c19de8d23eb5a41be8a5", size = 2920132, upload-time = "2024-10-16T11:21:16.339Z" }, + { url = "https://files.pythonhosted.org/packages/2d/70/aa69c9f69cf09a01da224909ff6ce8b68faeef476f00f7ec377e8f03be70/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47", size = 2959312, upload-time = "2024-10-16T11:21:25.584Z" }, + { url = "https://files.pythonhosted.org/packages/d3/bd/213e59854fafe87ba47814bf413ace0dcee33a89c8c8c814faca6bc7cf3c/psycopg2_binary-2.9.10-cp312-cp312-win32.whl", hash = "sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64", size = 1025191, upload-time = "2024-10-16T11:21:29.912Z" }, + { url = "https://files.pythonhosted.org/packages/92/29/06261ea000e2dc1e22907dbbc483a1093665509ea586b29b8986a0e56733/psycopg2_binary-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0", size = 1164031, upload-time = "2024-10-16T11:21:34.211Z" }, + { url = "https://files.pythonhosted.org/packages/3e/30/d41d3ba765609c0763505d565c4d12d8f3c79793f0d0f044ff5a28bf395b/psycopg2_binary-2.9.10-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d", size = 3044699, upload-time = "2024-10-16T11:21:42.841Z" }, + { url = "https://files.pythonhosted.org/packages/35/44/257ddadec7ef04536ba71af6bc6a75ec05c5343004a7ec93006bee66c0bc/psycopg2_binary-2.9.10-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb", size = 3275245, upload-time = "2024-10-16T11:21:51.989Z" }, + { url = "https://files.pythonhosted.org/packages/1b/11/48ea1cd11de67f9efd7262085588790a95d9dfcd9b8a687d46caf7305c1a/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7", size = 2851631, upload-time = "2024-10-16T11:21:57.584Z" }, + { url = "https://files.pythonhosted.org/packages/62/e0/62ce5ee650e6c86719d621a761fe4bc846ab9eff8c1f12b1ed5741bf1c9b/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d", size = 3082140, upload-time = "2024-10-16T11:22:02.005Z" }, + { url = "https://files.pythonhosted.org/packages/27/ce/63f946c098611f7be234c0dd7cb1ad68b0b5744d34f68062bb3c5aa510c8/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73", size = 3264762, upload-time = "2024-10-16T11:22:06.412Z" }, + { url = "https://files.pythonhosted.org/packages/43/25/c603cd81402e69edf7daa59b1602bd41eb9859e2824b8c0855d748366ac9/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673", size = 3020967, upload-time = "2024-10-16T11:22:11.583Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d6/8708d8c6fca531057fa170cdde8df870e8b6a9b136e82b361c65e42b841e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f", size = 2872326, upload-time = "2024-10-16T11:22:16.406Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ac/5b1ea50fc08a9df82de7e1771537557f07c2632231bbab652c7e22597908/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909", size = 2822712, upload-time = "2024-10-16T11:22:21.366Z" }, + { url = "https://files.pythonhosted.org/packages/c4/fc/504d4503b2abc4570fac3ca56eb8fed5e437bf9c9ef13f36b6621db8ef00/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1", size = 2920155, upload-time = "2024-10-16T11:22:25.684Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d1/323581e9273ad2c0dbd1902f3fb50c441da86e894b6e25a73c3fda32c57e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567", size = 2959356, upload-time = "2024-10-16T11:22:30.562Z" }, + { url = "https://files.pythonhosted.org/packages/08/50/d13ea0a054189ae1bc21af1d85b6f8bb9bbc5572991055d70ad9006fe2d6/psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142", size = 2569224, upload-time = "2025-01-04T20:09:19.234Z" }, +] + +[[package]] +name = "py-cpuinfo" +version = "9.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", size = 104716, upload-time = "2022-10-25T20:38:06.303Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", size = 22335, upload-time = "2022-10-25T20:38:27.636Z" }, +] + +[[package]] +name = "pyarrow" +version = "21.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/c2/ea068b8f00905c06329a3dfcd40d0fcc2b7d0f2e355bdb25b65e0a0e4cd4/pyarrow-21.0.0.tar.gz", hash = "sha256:5051f2dccf0e283ff56335760cbc8622cf52264d67e359d5569541ac11b6d5bc", size = 1133487, upload-time = "2025-07-18T00:57:31.761Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/d4/d4f817b21aacc30195cf6a46ba041dd1be827efa4a623cc8bf39a1c2a0c0/pyarrow-21.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:3a302f0e0963db37e0a24a70c56cf91a4faa0bca51c23812279ca2e23481fccd", size = 31160305, upload-time = "2025-07-18T00:55:35.373Z" }, + { url = "https://files.pythonhosted.org/packages/a2/9c/dcd38ce6e4b4d9a19e1d36914cb8e2b1da4e6003dd075474c4cfcdfe0601/pyarrow-21.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:b6b27cf01e243871390474a211a7922bfbe3bda21e39bc9160daf0da3fe48876", size = 32684264, upload-time = "2025-07-18T00:55:39.303Z" }, + { url = "https://files.pythonhosted.org/packages/4f/74/2a2d9f8d7a59b639523454bec12dba35ae3d0a07d8ab529dc0809f74b23c/pyarrow-21.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e72a8ec6b868e258a2cd2672d91f2860ad532d590ce94cdf7d5e7ec674ccf03d", size = 41108099, upload-time = "2025-07-18T00:55:42.889Z" }, + { url = "https://files.pythonhosted.org/packages/ad/90/2660332eeb31303c13b653ea566a9918484b6e4d6b9d2d46879a33ab0622/pyarrow-21.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b7ae0bbdc8c6674259b25bef5d2a1d6af5d39d7200c819cf99e07f7dfef1c51e", size = 42829529, upload-time = "2025-07-18T00:55:47.069Z" }, + { url = "https://files.pythonhosted.org/packages/33/27/1a93a25c92717f6aa0fca06eb4700860577d016cd3ae51aad0e0488ac899/pyarrow-21.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:58c30a1729f82d201627c173d91bd431db88ea74dcaa3885855bc6203e433b82", size = 43367883, upload-time = "2025-07-18T00:55:53.069Z" }, + { url = "https://files.pythonhosted.org/packages/05/d9/4d09d919f35d599bc05c6950095e358c3e15148ead26292dfca1fb659b0c/pyarrow-21.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:072116f65604b822a7f22945a7a6e581cfa28e3454fdcc6939d4ff6090126623", size = 45133802, upload-time = "2025-07-18T00:55:57.714Z" }, + { url = "https://files.pythonhosted.org/packages/71/30/f3795b6e192c3ab881325ffe172e526499eb3780e306a15103a2764916a2/pyarrow-21.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf56ec8b0a5c8c9d7021d6fd754e688104f9ebebf1bf4449613c9531f5346a18", size = 26203175, upload-time = "2025-07-18T00:56:01.364Z" }, + { url = "https://files.pythonhosted.org/packages/16/ca/c7eaa8e62db8fb37ce942b1ea0c6d7abfe3786ca193957afa25e71b81b66/pyarrow-21.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:e99310a4ebd4479bcd1964dff9e14af33746300cb014aa4a3781738ac63baf4a", size = 31154306, upload-time = "2025-07-18T00:56:04.42Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e8/e87d9e3b2489302b3a1aea709aaca4b781c5252fcb812a17ab6275a9a484/pyarrow-21.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:d2fe8e7f3ce329a71b7ddd7498b3cfac0eeb200c2789bd840234f0dc271a8efe", size = 32680622, upload-time = "2025-07-18T00:56:07.505Z" }, + { url = "https://files.pythonhosted.org/packages/84/52/79095d73a742aa0aba370c7942b1b655f598069489ab387fe47261a849e1/pyarrow-21.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:f522e5709379d72fb3da7785aa489ff0bb87448a9dc5a75f45763a795a089ebd", size = 41104094, upload-time = "2025-07-18T00:56:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/89/4b/7782438b551dbb0468892a276b8c789b8bbdb25ea5c5eb27faadd753e037/pyarrow-21.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:69cbbdf0631396e9925e048cfa5bce4e8c3d3b41562bbd70c685a8eb53a91e61", size = 42825576, upload-time = "2025-07-18T00:56:15.569Z" }, + { url = "https://files.pythonhosted.org/packages/b3/62/0f29de6e0a1e33518dec92c65be0351d32d7ca351e51ec5f4f837a9aab91/pyarrow-21.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:731c7022587006b755d0bdb27626a1a3bb004bb56b11fb30d98b6c1b4718579d", size = 43368342, upload-time = "2025-07-18T00:56:19.531Z" }, + { url = "https://files.pythonhosted.org/packages/90/c7/0fa1f3f29cf75f339768cc698c8ad4ddd2481c1742e9741459911c9ac477/pyarrow-21.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc56bc708f2d8ac71bd1dcb927e458c93cec10b98eb4120206a4091db7b67b99", size = 45131218, upload-time = "2025-07-18T00:56:23.347Z" }, + { url = "https://files.pythonhosted.org/packages/01/63/581f2076465e67b23bc5a37d4a2abff8362d389d29d8105832e82c9c811c/pyarrow-21.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:186aa00bca62139f75b7de8420f745f2af12941595bbbfa7ed3870ff63e25636", size = 26087551, upload-time = "2025-07-18T00:56:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ab/357d0d9648bb8241ee7348e564f2479d206ebe6e1c47ac5027c2e31ecd39/pyarrow-21.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:a7a102574faa3f421141a64c10216e078df467ab9576684d5cd696952546e2da", size = 31290064, upload-time = "2025-07-18T00:56:30.214Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8a/5685d62a990e4cac2043fc76b4661bf38d06efed55cf45a334b455bd2759/pyarrow-21.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:1e005378c4a2c6db3ada3ad4c217b381f6c886f0a80d6a316fe586b90f77efd7", size = 32727837, upload-time = "2025-07-18T00:56:33.935Z" }, + { url = "https://files.pythonhosted.org/packages/fc/de/c0828ee09525c2bafefd3e736a248ebe764d07d0fd762d4f0929dbc516c9/pyarrow-21.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:65f8e85f79031449ec8706b74504a316805217b35b6099155dd7e227eef0d4b6", size = 41014158, upload-time = "2025-07-18T00:56:37.528Z" }, + { url = "https://files.pythonhosted.org/packages/6e/26/a2865c420c50b7a3748320b614f3484bfcde8347b2639b2b903b21ce6a72/pyarrow-21.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:3a81486adc665c7eb1a2bde0224cfca6ceaba344a82a971ef059678417880eb8", size = 42667885, upload-time = "2025-07-18T00:56:41.483Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f9/4ee798dc902533159250fb4321267730bc0a107d8c6889e07c3add4fe3a5/pyarrow-21.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fc0d2f88b81dcf3ccf9a6ae17f89183762c8a94a5bdcfa09e05cfe413acf0503", size = 43276625, upload-time = "2025-07-18T00:56:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/5a/da/e02544d6997037a4b0d22d8e5f66bc9315c3671371a8b18c79ade1cefe14/pyarrow-21.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6299449adf89df38537837487a4f8d3bd91ec94354fdd2a7d30bc11c48ef6e79", size = 44951890, upload-time = "2025-07-18T00:56:52.568Z" }, + { url = "https://files.pythonhosted.org/packages/e5/4e/519c1bc1876625fe6b71e9a28287c43ec2f20f73c658b9ae1d485c0c206e/pyarrow-21.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:222c39e2c70113543982c6b34f3077962b44fca38c0bd9e68bb6781534425c10", size = 26371006, upload-time = "2025-07-18T00:56:56.379Z" }, +] + +[[package]] +name = "pyasn1" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/54/ecab642b3bed45f7d5f59b38443dcb36ef50f85af192e6ece103dbfe9587/pydantic-2.11.10.tar.gz", hash = "sha256:dc280f0982fbda6c38fada4e476dc0a4f3aeaf9c6ad4c28df68a666ec3c61423", size = 788494, upload-time = "2025-10-04T10:40:41.338Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/1f/73c53fcbfb0b5a78f91176df41945ca466e71e9d9d836e5c522abda39ee7/pydantic-2.11.10-py3-none-any.whl", hash = "sha256:802a655709d49bd004c31e865ef37da30b540786a46bfce02333e0e24b5fe29a", size = 444823, upload-time = "2025-10-04T10:40:39.055Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyiceberg" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "click" }, + { name = "fsspec" }, + { name = "mmh3" }, + { name = "pydantic" }, + { name = "pyparsing" }, + { name = "pyroaring" }, + { name = "requests" }, + { name = "rich" }, + { name = "sortedcontainers" }, + { name = "strictyaml" }, + { name = "tenacity" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/0e/90e61c38504f4fbd5ed79631f85da7d5ea5e5bf997bdeaa65b28ebf04cab/pyiceberg-0.10.0.tar.gz", hash = "sha256:2525afa5e7e5fc4e72b291f8e1cc219e982d2bda5ff17e62cd05b8d91c4139f5", size = 842633, upload-time = "2025-09-11T14:59:34.044Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/61/f5042dd09cb91deed908a39acd5012f1ac6910ddf84ada889751732f0df8/pyiceberg-0.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:64cad9d1db08192605875a872152cbcaca147ea486cfa94773fa5f4f65d78a23", size = 629281, upload-time = "2025-09-11T14:59:17.585Z" }, + { url = "https://files.pythonhosted.org/packages/8e/50/960f7239eedd4b1bab2a611f5e100fffc138549c1213760a57cd24a5bac1/pyiceberg-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3e12cf585318f0f48d31a77b4149e0e5b4c41e03a24aa8612e060f20ff41eb10", size = 623424, upload-time = "2025-09-11T14:59:19.045Z" }, + { url = "https://files.pythonhosted.org/packages/f5/2b/756a74c80db6edd82c8d3f23c3ae13e7d6620300b87ef792c2a4d3935b30/pyiceberg-0.10.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6979dd741cee263c1235595f71888c73365f2725697411027c4bd81046db3294", size = 1377048, upload-time = "2025-09-11T14:59:20.541Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/9c18cb4ddc7d371db63714abb2f5e8414bc7a4d63f474644a2aea2933fe6/pyiceberg-0.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:13fd03ec3da6eb4d3b55ff94b647946a7749bede5d743c75b39deaad26421200", size = 1369921, upload-time = "2025-09-11T14:59:22.134Z" }, + { url = "https://files.pythonhosted.org/packages/7b/b3/c012dc6b5bc3d0a84821936789c753f5c44aec619b64fbcf7f90038d172e/pyiceberg-0.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:33367c84bcb0a2fbbe54cbbfe062691ab93b91a2e3d319bb546ec5b9b45b6057", size = 617722, upload-time = "2025-09-11T14:59:23.67Z" }, +] + +[package.optional-dependencies] +sql-sqlite = [ + { name = "sqlalchemy" }, +] + +[[package]] +name = "pyjwt" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/b3/6d2b3f149bc5413b0a29761c2c5832d8ce904a1d7f621e86616d96f505cc/pymdown_extensions-10.16.1.tar.gz", hash = "sha256:aace82bcccba3efc03e25d584e6a22d27a8e17caa3f4dd9f207e49b787aa9a91", size = 853277, upload-time = "2025-07-28T16:19:34.167Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/06/43084e6cbd4b3bc0e80f6be743b2e79fbc6eed8de9ad8c629939fa55d972/pymdown_extensions-10.16.1-py3-none-any.whl", hash = "sha256:d6ba157a6c03146a7fb122b2b9a121300056384eafeec9c9f9e584adfdb2a32d", size = 266178, upload-time = "2025-07-28T16:19:31.401Z" }, +] + +[[package]] +name = "pyopenssl" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography", version = "45.0.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14' and platform_python_implementation != 'PyPy'" }, + { name = "cryptography", version = "46.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.14' or platform_python_implementation == 'PyPy'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/be/97b83a464498a79103036bc74d1038df4a7ef0e402cfaf4d5e113fb14759/pyopenssl-25.3.0.tar.gz", hash = "sha256:c981cb0a3fd84e8602d7afc209522773b94c1c2446a3c710a75b06fe1beae329", size = 184073, upload-time = "2025-09-17T00:32:21.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/81/ef2b1dfd1862567d573a4fdbc9f969067621764fbb74338496840a1d2977/pyopenssl-25.3.0-py3-none-any.whl", hash = "sha256:1fda6fc034d5e3d179d39e59c1895c9faeaf40a79de5fc4cbbfbe0d36f4a77b6", size = 57268, upload-time = "2025-09-17T00:32:19.474Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.2.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274, upload-time = "2025-09-21T04:11:06.277Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" }, +] + +[[package]] +name = "pyroaring" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/b2/5e0ab902f3899ba8a3e2bc3d901a9c66a902d5e5344c46900165ce506636/pyroaring-1.0.2.tar.gz", hash = "sha256:aa4a1de882bf4a245c7c0dee8594b898e76501bc32afc0cc9ff4138784462839", size = 188739, upload-time = "2025-06-30T21:37:04.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/a6/67c4df4c6e39c73d71f8941c94d6199b359c5d97fc261b879ac8263d4a15/pyroaring-1.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d9ec623abbfcf50771e460f202d41700bdfb7dc28c6f1b0be0843dd8b61d50ac", size = 730312, upload-time = "2025-06-30T21:35:57.69Z" }, + { url = "https://files.pythonhosted.org/packages/0e/3e/089a07b922890b511a3b5342f126bb5437b3000c01818e23437ccec45621/pyroaring-1.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:986a1245b22294ce5ba1b6f4299aea9a410d534718fce0fc6af6fe2251bb8981", size = 399737, upload-time = "2025-06-30T21:35:58.665Z" }, + { url = "https://files.pythonhosted.org/packages/58/90/69ba1f2b17ef91a038e718712cae047acbf7c1951b4075f586cf87b1f940/pyroaring-1.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:617b1affe6a09025a0207f6fa1d6f2266ef540c5ab9ab29287311f35825ae63a", size = 337115, upload-time = "2025-06-30T21:36:00.081Z" }, + { url = "https://files.pythonhosted.org/packages/0b/8b/f8367f926b17a8191242a3c637685ede4dac4c7140743c676fd77eb87e9b/pyroaring-1.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67c0782b46e552c71d2598f50cad326446364fab02ec51b37ec26037d78263bc", size = 1903327, upload-time = "2025-06-30T21:36:01.133Z" }, + { url = "https://files.pythonhosted.org/packages/de/cd/a3a704bb38bf9ebcc6e01c3d7025df68f2d952196e71d143e3ea98845a36/pyroaring-1.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47fe576f01b806c5677e08cc60d3765f872f7aeef9204914dacb3ba72067d4b0", size = 2116802, upload-time = "2025-06-30T21:36:02.276Z" }, + { url = "https://files.pythonhosted.org/packages/6a/2e/ac3402868f9b643ff06d2e2c6807534f2ee906de4cd6ca3ad42ac3a9610b/pyroaring-1.0.2-cp312-cp312-manylinux_2_24_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:96291b1f4f77ca13ceb3716605bcb63ae91e17c9539bd07fc77509226a7e8d1f", size = 1826895, upload-time = "2025-06-30T21:36:03.408Z" }, + { url = "https://files.pythonhosted.org/packages/29/d1/e94cd7a422bb0449f818839186e08cc59e6081f3009377511d10dadb9c22/pyroaring-1.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbf02fc3873efefe37429a91d1c384c6c259b3e5b5f4220c9436550b5c480aa3", size = 1842686, upload-time = "2025-06-30T21:36:04.541Z" }, + { url = "https://files.pythonhosted.org/packages/58/8b/d7036366ec86c73a66eefd1b63888d2995b1a41386020c7c3cfe3d4e5d55/pyroaring-1.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0ce11a6d57d6d89759eeb87a727d1657cb1f03ced71d186812799e07879c568e", size = 2901228, upload-time = "2025-06-30T21:36:05.712Z" }, + { url = "https://files.pythonhosted.org/packages/5f/0e/1ea50782e2ae8d330d67b373c331fdd90949d2e8f464f2115a89ead68944/pyroaring-1.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:decefea17be7ec3cfe461022ebb73d369f0fe07d39ba813d168267ff82a3f748", size = 2730377, upload-time = "2025-06-30T21:36:06.837Z" }, + { url = "https://files.pythonhosted.org/packages/07/cb/1ad8c19660443875f1e8be6cef981b2f17385270ccf85b678073acbe129d/pyroaring-1.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:04e6b56384aab6ca2f37e4d868b49689a0e9cf4198d8fdb2f6475a8f13d937ba", size = 3040183, upload-time = "2025-06-30T21:36:08.103Z" }, + { url = "https://files.pythonhosted.org/packages/52/18/da6c6a0310c4ba7e9acea91f10fd0a77fc072117a9975048cf87e00744c6/pyroaring-1.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b7d74f12761ee614ebd6337641100c370bc982099fbb109cdd9b23b40ae96273", size = 3178746, upload-time = "2025-06-30T21:36:09.712Z" }, + { url = "https://files.pythonhosted.org/packages/23/79/3ff3e39afa9829024392de626acf64178f118c1be581220c0ef486d4abd5/pyroaring-1.0.2-cp312-cp312-win32.whl", hash = "sha256:5a5facb5d5c529f4b6967ce75f76806bf8161694dc3d5d4c0f9de3cf614b7735", size = 226760, upload-time = "2025-06-30T21:36:10.797Z" }, + { url = "https://files.pythonhosted.org/packages/d9/c2/0b1fd43748163c155a262c31c6b0467604efd00b331a855a54a8619aafd9/pyroaring-1.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:906f07c97487fd0319aa36e36f8ed54b9fdf275297b394cf36803592527b186c", size = 282496, upload-time = "2025-06-30T21:36:12.073Z" }, + { url = "https://files.pythonhosted.org/packages/34/ce/b6d257945213990016d4692ea57c55e8f2f1258e3bf9db7b4e8f87945a16/pyroaring-1.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:51ed8a5677c409c4b896e931b4baaa0f95f6a4c8fe56b6dc0e7f8f6728487465", size = 236781, upload-time = "2025-06-30T21:36:13.283Z" }, + { url = "https://files.pythonhosted.org/packages/c9/f4/e0db58f062971393dea656515b0d5b35d52eb31486d179747a00768c479a/pyroaring-1.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f14a300354b2c23de16cc421dc54af4987cb3da4d90df9eddf3bb081a664093d", size = 727533, upload-time = "2025-06-30T21:36:14.254Z" }, + { url = "https://files.pythonhosted.org/packages/be/2e/0001d7caf3b0b02cfcf956a67dfdb1e9f3dacc943b63b6e773c4a7254331/pyroaring-1.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:987fc92e443dfcea57b31bd7f0b06e1d46b7361c7d1b3adf5c9d49614195e7ff", size = 398062, upload-time = "2025-06-30T21:36:15.306Z" }, + { url = "https://files.pythonhosted.org/packages/1a/1f/b2d49562990fe162ca303ad9765f890e176e3ee95c273729e3756802b4a9/pyroaring-1.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bc40e70fe9917f32776f741ce93acf1de8897260cadf27397252f1e4125a91da", size = 336237, upload-time = "2025-06-30T21:36:16.622Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d6/dc6615e8104d03031595863788206e01dda8287b4c7b208ba4085ecbd8b7/pyroaring-1.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b482f64a08bd23e3ff7a025fd431da048d4ee7b0dd6e75e83182b1ff418008b", size = 1899052, upload-time = "2025-06-30T21:36:17.626Z" }, + { url = "https://files.pythonhosted.org/packages/7a/a8/a56beb6a860f6a25d5c225bdafd06b26e12e0eddc250cbdf36c3016fd9eb/pyroaring-1.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f9b1a1d309b29de793e2958c1e9808218c449a7516f682627a18ea5782b0e2a", size = 2113972, upload-time = "2025-06-30T21:36:19.126Z" }, + { url = "https://files.pythonhosted.org/packages/7a/6e/8953623b551ed46d9fed825f6164e0f3f78763f40c930c08890e2a91ba22/pyroaring-1.0.2-cp313-cp313-manylinux_2_24_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cf4822333443ff7cdedce36da8365a442ad40e8c42fb1b835a589892cb08de65", size = 1824078, upload-time = "2025-06-30T21:36:20.197Z" }, + { url = "https://files.pythonhosted.org/packages/03/b7/05d49c5a4f45bfc163b6b91a1d17875da10e4a250860cf4e27faabddb51d/pyroaring-1.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3695317b9f8a95ced9ab2426fcae59f23b540c8d812178e607e090f5546f2359", size = 1838024, upload-time = "2025-06-30T21:36:21.249Z" }, + { url = "https://files.pythonhosted.org/packages/d5/15/0e1953ea05db6251ffca0e6ec2311b3e3d0a87c47efc9e180d6565478a2d/pyroaring-1.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:83d92fdf6c236e539fe3258375fd407b822dd7207cbed56a520d364b7cf3a516", size = 2893993, upload-time = "2025-06-30T21:36:23.087Z" }, + { url = "https://files.pythonhosted.org/packages/ea/70/6a604abefd891ad1667950aa9a899b51a12ac61a51dca7938b7b95420339/pyroaring-1.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2bc091dab0811359f4fbabbf771485b12e2086c5bd2f27570cca8860e56e3837", size = 2724192, upload-time = "2025-06-30T21:36:24.627Z" }, + { url = "https://files.pythonhosted.org/packages/94/44/9455f728271958e160ca1724750885261cadbb73a029186ac2c7aef0880d/pyroaring-1.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f1744c415b75e4cd3b3d26c2d7a2cda6c8f3e6a713e42751189adfe1d41954e7", size = 3040825, upload-time = "2025-06-30T21:36:25.883Z" }, + { url = "https://files.pythonhosted.org/packages/ad/db/6b2e7ab6c45102601cc5ea8a806bcc1cd23c6c07d9c9e9900e91f35d4d3f/pyroaring-1.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:25b223c71a34e0bf4fe004312723918941337ae4770ec22e1ae43050fc45422f", size = 3175409, upload-time = "2025-06-30T21:36:27.091Z" }, + { url = "https://files.pythonhosted.org/packages/1a/2f/c3bb6a1ba74b2496c2c97c7b2628efef22b73badd77265fdac509ad53aed/pyroaring-1.0.2-cp313-cp313-win32.whl", hash = "sha256:41e96f770240d773c13137250dd0c51ab898c435d48d77eae37853939a9bb402", size = 226593, upload-time = "2025-06-30T21:36:28.179Z" }, + { url = "https://files.pythonhosted.org/packages/ef/bf/5a4283dfbadd873c24475b146911e6f5629f3b5cc0d49a72fce3b143995a/pyroaring-1.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:a73ce95a6205f2b341147619790ecc75e96a9ca265f9797fc816324df6c26c38", size = 281992, upload-time = "2025-06-30T21:36:29.091Z" }, + { url = "https://files.pythonhosted.org/packages/4d/2c/5de12c135920e6098e3bd6400ef398e87fe0b81c0cdc2e092e3d5050a60c/pyroaring-1.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:3912f2ea93b27b57e914b7d082a6849ff9048644c803de8bb85d7a15cdb420bd", size = 236755, upload-time = "2025-06-30T21:36:30.387Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" }, +] + +[[package]] +name = "pytest-benchmark" +version = "5.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "py-cpuinfo" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/d0/a8bd08d641b393db3be3819b03e2d9bb8760ca8479080a26a5f6e540e99c/pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105", size = 337810, upload-time = "2024-10-30T11:51:48.521Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/d6/b41653199ea09d5969d4e385df9bbfd9a100f28ca7e824ce7c0a016e3053/pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89", size = 44259, upload-time = "2024-10-30T11:51:45.94Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "pytest-mock" +version = "3.15.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", size = 34036, upload-time = "2025-09-16T16:37:27.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", size = 10095, upload-time = "2025-09-16T16:37:25.734Z" }, +] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, +] + +[[package]] +name = "pytokens" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a", size = 17644, upload-time = "2025-11-05T13:36:35.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" }, +] + +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, +] + +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { 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" }, + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, +] + +[[package]] +name = "pyyaml" +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/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" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "redis" +version = "6.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/d6/e8b92798a5bd67d659d51a18170e91c16ac3b59738d91894651ee255ed49/redis-6.4.0.tar.gz", hash = "sha256:b01bc7282b8444e28ec36b261df5375183bb47a07eb9c603f284e89cbc5ef010", size = 4647399, upload-time = "2025-08-07T08:10:11.441Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl", hash = "sha256:f0544fa9604264e9464cdf4814e7d4830f74b165d52f2a330a760a88dd248b7f", size = 279847, upload-time = "2025-08-07T08:10:09.84Z" }, +] + +[[package]] +name = "referencing" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "respx" +version = "0.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/7c/96bd0bc759cf009675ad1ee1f96535edcb11e9666b985717eb8c87192a95/respx-0.22.0.tar.gz", hash = "sha256:3c8924caa2a50bd71aefc07aa812f2466ff489f1848c96e954a5362d17095d91", size = 28439, upload-time = "2024-12-19T22:33:59.374Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/67/afbb0978d5399bc9ea200f1d4489a23c9a1dad4eee6376242b8182389c79/respx-0.22.0-py2.py3-none-any.whl", hash = "sha256:631128d4c9aba15e56903fb5f66fb1eff412ce28dd387ca3a81339e52dbd3ad0", size = 25127, upload-time = "2024-12-19T22:33:57.837Z" }, +] + +[[package]] +name = "rich" +version = "14.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/dd/2c0cbe774744272b0ae725f44032c77bdcab6e8bcf544bffa3b6e70c8dba/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8", size = 27479, upload-time = "2025-08-27T12:16:36.024Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/fe/38de28dee5df58b8198c743fe2bea0c785c6d40941b9950bac4cdb71a014/rpds_py-0.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ae2775c1973e3c30316892737b91f9283f9908e3cc7625b9331271eaaed7dc90", size = 361887, upload-time = "2025-08-27T12:13:10.233Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/4b6c7eedc7dd90986bf0fab6ea2a091ec11c01b15f8ba0a14d3f80450468/rpds_py-0.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2643400120f55c8a96f7c9d858f7be0c88d383cd4653ae2cf0d0c88f668073e5", size = 345795, upload-time = "2025-08-27T12:13:11.65Z" }, + { url = "https://files.pythonhosted.org/packages/6f/0e/e650e1b81922847a09cca820237b0edee69416a01268b7754d506ade11ad/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16323f674c089b0360674a4abd28d5042947d54ba620f72514d69be4ff64845e", size = 385121, upload-time = "2025-08-27T12:13:13.008Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ea/b306067a712988e2bff00dcc7c8f31d26c29b6d5931b461aa4b60a013e33/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a1f4814b65eacac94a00fc9a526e3fdafd78e439469644032032d0d63de4881", size = 398976, upload-time = "2025-08-27T12:13:14.368Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0a/26dc43c8840cb8fe239fe12dbc8d8de40f2365e838f3d395835dde72f0e5/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba32c16b064267b22f1850a34051121d423b6f7338a12b9459550eb2096e7ec", size = 525953, upload-time = "2025-08-27T12:13:15.774Z" }, + { url = "https://files.pythonhosted.org/packages/22/14/c85e8127b573aaf3a0cbd7fbb8c9c99e735a4a02180c84da2a463b766e9e/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5c20f33fd10485b80f65e800bbe5f6785af510b9f4056c5a3c612ebc83ba6cb", size = 407915, upload-time = "2025-08-27T12:13:17.379Z" }, + { url = "https://files.pythonhosted.org/packages/ed/7b/8f4fee9ba1fb5ec856eb22d725a4efa3deb47f769597c809e03578b0f9d9/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466bfe65bd932da36ff279ddd92de56b042f2266d752719beb97b08526268ec5", size = 386883, upload-time = "2025-08-27T12:13:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/86/47/28fa6d60f8b74fcdceba81b272f8d9836ac0340570f68f5df6b41838547b/rpds_py-0.27.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:41e532bbdcb57c92ba3be62c42e9f096431b4cf478da9bc3bc6ce5c38ab7ba7a", size = 405699, upload-time = "2025-08-27T12:13:20.089Z" }, + { url = "https://files.pythonhosted.org/packages/d0/fd/c5987b5e054548df56953a21fe2ebed51fc1ec7c8f24fd41c067b68c4a0a/rpds_py-0.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f149826d742b406579466283769a8ea448eed82a789af0ed17b0cd5770433444", size = 423713, upload-time = "2025-08-27T12:13:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ba/3c4978b54a73ed19a7d74531be37a8bcc542d917c770e14d372b8daea186/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80c60cfb5310677bd67cb1e85a1e8eb52e12529545441b43e6f14d90b878775a", size = 562324, upload-time = "2025-08-27T12:13:22.789Z" }, + { url = "https://files.pythonhosted.org/packages/b5/6c/6943a91768fec16db09a42b08644b960cff540c66aab89b74be6d4a144ba/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7ee6521b9baf06085f62ba9c7a3e5becffbc32480d2f1b351559c001c38ce4c1", size = 593646, upload-time = "2025-08-27T12:13:24.122Z" }, + { url = "https://files.pythonhosted.org/packages/11/73/9d7a8f4be5f4396f011a6bb7a19fe26303a0dac9064462f5651ced2f572f/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a512c8263249a9d68cac08b05dd59d2b3f2061d99b322813cbcc14c3c7421998", size = 558137, upload-time = "2025-08-27T12:13:25.557Z" }, + { url = "https://files.pythonhosted.org/packages/6e/96/6772cbfa0e2485bcceef8071de7821f81aeac8bb45fbfd5542a3e8108165/rpds_py-0.27.1-cp312-cp312-win32.whl", hash = "sha256:819064fa048ba01b6dadc5116f3ac48610435ac9a0058bbde98e569f9e785c39", size = 221343, upload-time = "2025-08-27T12:13:26.967Z" }, + { url = "https://files.pythonhosted.org/packages/67/b6/c82f0faa9af1c6a64669f73a17ee0eeef25aff30bb9a1c318509efe45d84/rpds_py-0.27.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9199717881f13c32c4046a15f024971a3b78ad4ea029e8da6b86e5aa9cf4594", size = 232497, upload-time = "2025-08-27T12:13:28.326Z" }, + { url = "https://files.pythonhosted.org/packages/e1/96/2817b44bd2ed11aebacc9251da03689d56109b9aba5e311297b6902136e2/rpds_py-0.27.1-cp312-cp312-win_arm64.whl", hash = "sha256:33aa65b97826a0e885ef6e278fbd934e98cdcfed80b63946025f01e2f5b29502", size = 222790, upload-time = "2025-08-27T12:13:29.71Z" }, + { url = "https://files.pythonhosted.org/packages/cc/77/610aeee8d41e39080c7e14afa5387138e3c9fa9756ab893d09d99e7d8e98/rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b", size = 361741, upload-time = "2025-08-27T12:13:31.039Z" }, + { url = "https://files.pythonhosted.org/packages/3a/fc/c43765f201c6a1c60be2043cbdb664013def52460a4c7adace89d6682bf4/rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf", size = 345574, upload-time = "2025-08-27T12:13:32.902Z" }, + { url = "https://files.pythonhosted.org/packages/20/42/ee2b2ca114294cd9847d0ef9c26d2b0851b2e7e00bf14cc4c0b581df0fc3/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83", size = 385051, upload-time = "2025-08-27T12:13:34.228Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e8/1e430fe311e4799e02e2d1af7c765f024e95e17d651612425b226705f910/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf", size = 398395, upload-time = "2025-08-27T12:13:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/82/95/9dc227d441ff2670651c27a739acb2535ccaf8b351a88d78c088965e5996/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2", size = 524334, upload-time = "2025-08-27T12:13:37.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/01/a670c232f401d9ad461d9a332aa4080cd3cb1d1df18213dbd0d2a6a7ab51/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0", size = 407691, upload-time = "2025-08-27T12:13:38.94Z" }, + { url = "https://files.pythonhosted.org/packages/03/36/0a14aebbaa26fe7fab4780c76f2239e76cc95a0090bdb25e31d95c492fcd/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418", size = 386868, upload-time = "2025-08-27T12:13:40.192Z" }, + { url = "https://files.pythonhosted.org/packages/3b/03/8c897fb8b5347ff6c1cc31239b9611c5bf79d78c984430887a353e1409a1/rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d", size = 405469, upload-time = "2025-08-27T12:13:41.496Z" }, + { url = "https://files.pythonhosted.org/packages/da/07/88c60edc2df74850d496d78a1fdcdc7b54360a7f610a4d50008309d41b94/rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274", size = 422125, upload-time = "2025-08-27T12:13:42.802Z" }, + { url = "https://files.pythonhosted.org/packages/6b/86/5f4c707603e41b05f191a749984f390dabcbc467cf833769b47bf14ba04f/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd", size = 562341, upload-time = "2025-08-27T12:13:44.472Z" }, + { url = "https://files.pythonhosted.org/packages/b2/92/3c0cb2492094e3cd9baf9e49bbb7befeceb584ea0c1a8b5939dca4da12e5/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2", size = 592511, upload-time = "2025-08-27T12:13:45.898Z" }, + { url = "https://files.pythonhosted.org/packages/10/bb/82e64fbb0047c46a168faa28d0d45a7851cd0582f850b966811d30f67ad8/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002", size = 557736, upload-time = "2025-08-27T12:13:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/00/95/3c863973d409210da7fb41958172c6b7dbe7fc34e04d3cc1f10bb85e979f/rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3", size = 221462, upload-time = "2025-08-27T12:13:48.742Z" }, + { url = "https://files.pythonhosted.org/packages/ce/2c/5867b14a81dc217b56d95a9f2a40fdbc56a1ab0181b80132beeecbd4b2d6/rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83", size = 232034, upload-time = "2025-08-27T12:13:50.11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/78/3958f3f018c01923823f1e47f1cc338e398814b92d83cd278364446fac66/rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d", size = 222392, upload-time = "2025-08-27T12:13:52.587Z" }, + { url = "https://files.pythonhosted.org/packages/01/76/1cdf1f91aed5c3a7bf2eba1f1c4e4d6f57832d73003919a20118870ea659/rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228", size = 358355, upload-time = "2025-08-27T12:13:54.012Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6f/bf142541229374287604caf3bb2a4ae17f0a580798fd72d3b009b532db4e/rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92", size = 342138, upload-time = "2025-08-27T12:13:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/1a/77/355b1c041d6be40886c44ff5e798b4e2769e497b790f0f7fd1e78d17e9a8/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2", size = 380247, upload-time = "2025-08-27T12:13:57.683Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a4/d9cef5c3946ea271ce2243c51481971cd6e34f21925af2783dd17b26e815/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723", size = 390699, upload-time = "2025-08-27T12:13:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/3a/06/005106a7b8c6c1a7e91b73169e49870f4af5256119d34a361ae5240a0c1d/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802", size = 521852, upload-time = "2025-08-27T12:14:00.583Z" }, + { url = "https://files.pythonhosted.org/packages/e5/3e/50fb1dac0948e17a02eb05c24510a8fe12d5ce8561c6b7b7d1339ab7ab9c/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f", size = 402582, upload-time = "2025-08-27T12:14:02.034Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b0/f4e224090dc5b0ec15f31a02d746ab24101dd430847c4d99123798661bfc/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2", size = 384126, upload-time = "2025-08-27T12:14:03.437Z" }, + { url = "https://files.pythonhosted.org/packages/54/77/ac339d5f82b6afff1df8f0fe0d2145cc827992cb5f8eeb90fc9f31ef7a63/rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21", size = 399486, upload-time = "2025-08-27T12:14:05.443Z" }, + { url = "https://files.pythonhosted.org/packages/d6/29/3e1c255eee6ac358c056a57d6d6869baa00a62fa32eea5ee0632039c50a3/rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef", size = 414832, upload-time = "2025-08-27T12:14:06.902Z" }, + { url = "https://files.pythonhosted.org/packages/3f/db/6d498b844342deb3fa1d030598db93937a9964fcf5cb4da4feb5f17be34b/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081", size = 557249, upload-time = "2025-08-27T12:14:08.37Z" }, + { url = "https://files.pythonhosted.org/packages/60/f3/690dd38e2310b6f68858a331399b4d6dbb9132c3e8ef8b4333b96caf403d/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd", size = 587356, upload-time = "2025-08-27T12:14:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/86/e3/84507781cccd0145f35b1dc32c72675200c5ce8d5b30f813e49424ef68fc/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7", size = 555300, upload-time = "2025-08-27T12:14:11.783Z" }, + { url = "https://files.pythonhosted.org/packages/e5/ee/375469849e6b429b3516206b4580a79e9ef3eb12920ddbd4492b56eaacbe/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688", size = 216714, upload-time = "2025-08-27T12:14:13.629Z" }, + { url = "https://files.pythonhosted.org/packages/21/87/3fc94e47c9bd0742660e84706c311a860dcae4374cf4a03c477e23ce605a/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797", size = 228943, upload-time = "2025-08-27T12:14:14.937Z" }, + { url = "https://files.pythonhosted.org/packages/70/36/b6e6066520a07cf029d385de869729a895917b411e777ab1cde878100a1d/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334", size = 362472, upload-time = "2025-08-27T12:14:16.333Z" }, + { url = "https://files.pythonhosted.org/packages/af/07/b4646032e0dcec0df9c73a3bd52f63bc6c5f9cda992f06bd0e73fe3fbebd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33", size = 345676, upload-time = "2025-08-27T12:14:17.764Z" }, + { url = "https://files.pythonhosted.org/packages/b0/16/2f1003ee5d0af4bcb13c0cf894957984c32a6751ed7206db2aee7379a55e/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a", size = 385313, upload-time = "2025-08-27T12:14:19.829Z" }, + { url = "https://files.pythonhosted.org/packages/05/cd/7eb6dd7b232e7f2654d03fa07f1414d7dfc980e82ba71e40a7c46fd95484/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b", size = 399080, upload-time = "2025-08-27T12:14:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/20/51/5829afd5000ec1cb60f304711f02572d619040aa3ec033d8226817d1e571/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7", size = 523868, upload-time = "2025-08-27T12:14:23.485Z" }, + { url = "https://files.pythonhosted.org/packages/05/2c/30eebca20d5db95720ab4d2faec1b5e4c1025c473f703738c371241476a2/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136", size = 408750, upload-time = "2025-08-27T12:14:24.924Z" }, + { url = "https://files.pythonhosted.org/packages/90/1a/cdb5083f043597c4d4276eae4e4c70c55ab5accec078da8611f24575a367/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff", size = 387688, upload-time = "2025-08-27T12:14:27.537Z" }, + { url = "https://files.pythonhosted.org/packages/7c/92/cf786a15320e173f945d205ab31585cc43969743bb1a48b6888f7a2b0a2d/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9", size = 407225, upload-time = "2025-08-27T12:14:28.981Z" }, + { url = "https://files.pythonhosted.org/packages/33/5c/85ee16df5b65063ef26017bef33096557a4c83fbe56218ac7cd8c235f16d/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60", size = 423361, upload-time = "2025-08-27T12:14:30.469Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8e/1c2741307fcabd1a334ecf008e92c4f47bb6f848712cf15c923becfe82bb/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e", size = 562493, upload-time = "2025-08-27T12:14:31.987Z" }, + { url = "https://files.pythonhosted.org/packages/04/03/5159321baae9b2222442a70c1f988cbbd66b9be0675dd3936461269be360/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212", size = 592623, upload-time = "2025-08-27T12:14:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/ff/39/c09fd1ad28b85bc1d4554a8710233c9f4cefd03d7717a1b8fbfd171d1167/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675", size = 558800, upload-time = "2025-08-27T12:14:35.436Z" }, + { url = "https://files.pythonhosted.org/packages/c5/d6/99228e6bbcf4baa764b18258f519a9035131d91b538d4e0e294313462a98/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3", size = 221943, upload-time = "2025-08-27T12:14:36.898Z" }, + { url = "https://files.pythonhosted.org/packages/be/07/c802bc6b8e95be83b79bdf23d1aa61d68324cb1006e245d6c58e959e314d/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456", size = 233739, upload-time = "2025-08-27T12:14:38.386Z" }, + { url = "https://files.pythonhosted.org/packages/c8/89/3e1b1c16d4c2d547c5717377a8df99aee8099ff050f87c45cb4d5fa70891/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3", size = 223120, upload-time = "2025-08-27T12:14:39.82Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/dc7931dc2fa4a6e46b2a4fa744a9fe5c548efd70e0ba74f40b39fa4a8c10/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2", size = 358944, upload-time = "2025-08-27T12:14:41.199Z" }, + { url = "https://files.pythonhosted.org/packages/e6/22/4af76ac4e9f336bfb1a5f240d18a33c6b2fcaadb7472ac7680576512b49a/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4", size = 342283, upload-time = "2025-08-27T12:14:42.699Z" }, + { url = "https://files.pythonhosted.org/packages/1c/15/2a7c619b3c2272ea9feb9ade67a45c40b3eeb500d503ad4c28c395dc51b4/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e", size = 380320, upload-time = "2025-08-27T12:14:44.157Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7d/4c6d243ba4a3057e994bb5bedd01b5c963c12fe38dde707a52acdb3849e7/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817", size = 391760, upload-time = "2025-08-27T12:14:45.845Z" }, + { url = "https://files.pythonhosted.org/packages/b4/71/b19401a909b83bcd67f90221330bc1ef11bc486fe4e04c24388d28a618ae/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec", size = 522476, upload-time = "2025-08-27T12:14:47.364Z" }, + { url = "https://files.pythonhosted.org/packages/e4/44/1a3b9715c0455d2e2f0f6df5ee6d6f5afdc423d0773a8a682ed2b43c566c/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a", size = 403418, upload-time = "2025-08-27T12:14:49.991Z" }, + { url = "https://files.pythonhosted.org/packages/1c/4b/fb6c4f14984eb56673bc868a66536f53417ddb13ed44b391998100a06a96/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8", size = 384771, upload-time = "2025-08-27T12:14:52.159Z" }, + { url = "https://files.pythonhosted.org/packages/c0/56/d5265d2d28b7420d7b4d4d85cad8ef891760f5135102e60d5c970b976e41/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48", size = 400022, upload-time = "2025-08-27T12:14:53.859Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/9f5fc70164a569bdd6ed9046486c3568d6926e3a49bdefeeccfb18655875/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb", size = 416787, upload-time = "2025-08-27T12:14:55.673Z" }, + { url = "https://files.pythonhosted.org/packages/d4/64/56dd03430ba491db943a81dcdef115a985aac5f44f565cd39a00c766d45c/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734", size = 557538, upload-time = "2025-08-27T12:14:57.245Z" }, + { url = "https://files.pythonhosted.org/packages/3f/36/92cc885a3129993b1d963a2a42ecf64e6a8e129d2c7cc980dbeba84e55fb/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb", size = 588512, upload-time = "2025-08-27T12:14:58.728Z" }, + { url = "https://files.pythonhosted.org/packages/dd/10/6b283707780a81919f71625351182b4f98932ac89a09023cb61865136244/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0", size = 555813, upload-time = "2025-08-27T12:15:00.334Z" }, + { url = "https://files.pythonhosted.org/packages/04/2e/30b5ea18c01379da6272a92825dd7e53dc9d15c88a19e97932d35d430ef7/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a", size = 217385, upload-time = "2025-08-27T12:15:01.937Z" }, + { url = "https://files.pythonhosted.org/packages/32/7d/97119da51cb1dd3f2f3c0805f155a3aa4a95fa44fe7d78ae15e69edf4f34/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772", size = 230097, upload-time = "2025-08-27T12:15:03.961Z" }, +] + +[[package]] +name = "rsa" +version = "4.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/b9/9bd84453ed6dd04688de9b3f3a4146a1698e8faae2ceeccce4e14c67ae17/ruff-0.14.0.tar.gz", hash = "sha256:62ec8969b7510f77945df916de15da55311fade8d6050995ff7f680afe582c57", size = 5452071, upload-time = "2025-10-07T18:21:55.763Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/4e/79d463a5f80654e93fa653ebfb98e0becc3f0e7cf6219c9ddedf1e197072/ruff-0.14.0-py3-none-linux_armv6l.whl", hash = "sha256:58e15bffa7054299becf4bab8a1187062c6f8cafbe9f6e39e0d5aface455d6b3", size = 12494532, upload-time = "2025-10-07T18:21:00.373Z" }, + { url = "https://files.pythonhosted.org/packages/ee/40/e2392f445ed8e02aa6105d49db4bfff01957379064c30f4811c3bf38aece/ruff-0.14.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:838d1b065f4df676b7c9957992f2304e41ead7a50a568185efd404297d5701e8", size = 13160768, upload-time = "2025-10-07T18:21:04.73Z" }, + { url = "https://files.pythonhosted.org/packages/75/da/2a656ea7c6b9bd14c7209918268dd40e1e6cea65f4bb9880eaaa43b055cd/ruff-0.14.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:703799d059ba50f745605b04638fa7e9682cc3da084b2092feee63500ff3d9b8", size = 12363376, upload-time = "2025-10-07T18:21:07.833Z" }, + { url = "https://files.pythonhosted.org/packages/42/e2/1ffef5a1875add82416ff388fcb7ea8b22a53be67a638487937aea81af27/ruff-0.14.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ba9a8925e90f861502f7d974cc60e18ca29c72bb0ee8bfeabb6ade35a3abde7", size = 12608055, upload-time = "2025-10-07T18:21:10.72Z" }, + { url = "https://files.pythonhosted.org/packages/4a/32/986725199d7cee510d9f1dfdf95bf1efc5fa9dd714d0d85c1fb1f6be3bc3/ruff-0.14.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e41f785498bd200ffc276eb9e1570c019c1d907b07cfb081092c8ad51975bbe7", size = 12318544, upload-time = "2025-10-07T18:21:13.741Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ed/4969cefd53315164c94eaf4da7cfba1f267dc275b0abdd593d11c90829a3/ruff-0.14.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30a58c087aef4584c193aebf2700f0fbcfc1e77b89c7385e3139956fa90434e2", size = 14001280, upload-time = "2025-10-07T18:21:16.411Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ad/96c1fc9f8854c37681c9613d825925c7f24ca1acfc62a4eb3896b50bacd2/ruff-0.14.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f8d07350bc7af0a5ce8812b7d5c1a7293cf02476752f23fdfc500d24b79b783c", size = 15027286, upload-time = "2025-10-07T18:21:19.577Z" }, + { url = "https://files.pythonhosted.org/packages/b3/00/1426978f97df4fe331074baf69615f579dc4e7c37bb4c6f57c2aad80c87f/ruff-0.14.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eec3bbbf3a7d5482b5c1f42d5fc972774d71d107d447919fca620b0be3e3b75e", size = 14451506, upload-time = "2025-10-07T18:21:22.779Z" }, + { url = "https://files.pythonhosted.org/packages/58/d5/9c1cea6e493c0cf0647674cca26b579ea9d2a213b74b5c195fbeb9678e15/ruff-0.14.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16b68e183a0e28e5c176d51004aaa40559e8f90065a10a559176713fcf435206", size = 13437384, upload-time = "2025-10-07T18:21:25.758Z" }, + { url = "https://files.pythonhosted.org/packages/29/b4/4cd6a4331e999fc05d9d77729c95503f99eae3ba1160469f2b64866964e3/ruff-0.14.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb732d17db2e945cfcbbc52af0143eda1da36ca8ae25083dd4f66f1542fdf82e", size = 13447976, upload-time = "2025-10-07T18:21:28.83Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c0/ac42f546d07e4f49f62332576cb845d45c67cf5610d1851254e341d563b6/ruff-0.14.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:c958f66ab884b7873e72df38dcabee03d556a8f2ee1b8538ee1c2bbd619883dd", size = 13682850, upload-time = "2025-10-07T18:21:31.842Z" }, + { url = "https://files.pythonhosted.org/packages/5f/c4/4b0c9bcadd45b4c29fe1af9c5d1dc0ca87b4021665dfbe1c4688d407aa20/ruff-0.14.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7eb0499a2e01f6e0c285afc5bac43ab380cbfc17cd43a2e1dd10ec97d6f2c42d", size = 12449825, upload-time = "2025-10-07T18:21:35.074Z" }, + { url = "https://files.pythonhosted.org/packages/4b/a8/e2e76288e6c16540fa820d148d83e55f15e994d852485f221b9524514730/ruff-0.14.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4c63b2d99fafa05efca0ab198fd48fa6030d57e4423df3f18e03aa62518c565f", size = 12272599, upload-time = "2025-10-07T18:21:38.08Z" }, + { url = "https://files.pythonhosted.org/packages/18/14/e2815d8eff847391af632b22422b8207704222ff575dec8d044f9ab779b2/ruff-0.14.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:668fce701b7a222f3f5327f86909db2bbe99c30877c8001ff934c5413812ac02", size = 13193828, upload-time = "2025-10-07T18:21:41.216Z" }, + { url = "https://files.pythonhosted.org/packages/44/c6/61ccc2987cf0aecc588ff8f3212dea64840770e60d78f5606cd7dc34de32/ruff-0.14.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a86bf575e05cb68dcb34e4c7dfe1064d44d3f0c04bbc0491949092192b515296", size = 13628617, upload-time = "2025-10-07T18:21:44.04Z" }, + { url = "https://files.pythonhosted.org/packages/73/e6/03b882225a1b0627e75339b420883dc3c90707a8917d2284abef7a58d317/ruff-0.14.0-py3-none-win32.whl", hash = "sha256:7450a243d7125d1c032cb4b93d9625dea46c8c42b4f06c6b709baac168e10543", size = 12367872, upload-time = "2025-10-07T18:21:46.67Z" }, + { url = "https://files.pythonhosted.org/packages/41/77/56cf9cf01ea0bfcc662de72540812e5ba8e9563f33ef3d37ab2174892c47/ruff-0.14.0-py3-none-win_amd64.whl", hash = "sha256:ea95da28cd874c4d9c922b39381cbd69cb7e7b49c21b8152b014bd4f52acddc2", size = 13464628, upload-time = "2025-10-07T18:21:50.318Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2a/65880dfd0e13f7f13a775998f34703674a4554906167dce02daf7865b954/ruff-0.14.0-py3-none-win_arm64.whl", hash = "sha256:f42c9495f5c13ff841b1da4cb3c2a42075409592825dada7c5885c2c844ac730", size = 12565142, upload-time = "2025-10-07T18:21:53.577Z" }, +] + +[[package]] +name = "s3transfer" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/74/8d69dcb7a9efe8baa2046891735e5dfe433ad558ae23d9e3c14c633d1d58/s3transfer-0.14.0.tar.gz", hash = "sha256:eff12264e7c8b4985074ccce27a3b38a485bb7f7422cc8046fee9be4983e4125", size = 151547, upload-time = "2025-09-09T19:23:31.089Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/f0/ae7ca09223a81a1d890b2557186ea015f6e0502e9b8cb8e1813f1d8cfa4e/s3transfer-0.14.0-py3-none-any.whl", hash = "sha256:ea3b790c7077558ed1f02a3072fb3cb992bbbd253392f4b6e9e8976941c7d456", size = 85712, upload-time = "2025-09-09T19:23:30.041Z" }, +] + +[[package]] +name = "safe-pysha3" +version = "1.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a4/27/a942b8a95b97c5fb8d27d3b86b8d269546cf21f87d9ec6b44c3702ce67cc/safe_pysha3-1.0.5.tar.gz", hash = "sha256:88ceaad6af4b6bdecd2f54b31ad0e5e5e210d4f5ecabb1bd1fd3539ad61b7bf1", size = 827796, upload-time = "2025-06-19T13:55:04.106Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/59/8d7f64a3eb6ebbde248cc0347a67d7825e2ba6edfa2bd180ebdfb599b3c5/safe_pysha3-1.0.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d137a73029c6c5a1db5791ae9fa62373827eee5226d19b79b836a6cf48b6b197", size = 190427, upload-time = "2025-06-20T15:19:20.862Z" }, + { url = "https://files.pythonhosted.org/packages/da/6a/25e926ab9c8d714be2ee1d40f45eb425f438c968d97ede69a7cbff054094/safe_pysha3-1.0.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a0cb37252a8767992f354d7d2af2ef04730032927eb6af2057e71744c741287", size = 184478, upload-time = "2025-06-20T15:19:22.289Z" }, + { url = "https://files.pythonhosted.org/packages/3a/da/7e1f252e6984f4b82393e4e083d3a48806e8a7225651559e50dec0000c68/safe_pysha3-1.0.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2019065f1b7d3db37cc52d091c9d5526d5d36a3e1b9efcf0b345c24e03755bff", size = 190543, upload-time = "2025-06-20T15:19:23.426Z" }, + { url = "https://files.pythonhosted.org/packages/e6/a6/e134e353a4961090caf4f429044b845584fe11d2217960a2549943ef01ea/safe_pysha3-1.0.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa37d5d6138d5dd01d1035dba019b7525ad7c55669ded4524f589cddd13ea13b", size = 367223, upload-time = "2025-06-20T15:19:24.453Z" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "snowflake-connector-python" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asn1crypto" }, + { name = "boto3" }, + { name = "botocore" }, + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "cryptography", version = "45.0.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14' and platform_python_implementation != 'PyPy'" }, + { name = "cryptography", version = "46.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.14' or platform_python_implementation == 'PyPy'" }, + { name = "filelock" }, + { name = "idna" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "pyjwt" }, + { name = "pyopenssl" }, + { name = "pytz" }, + { name = "requests" }, + { name = "sortedcontainers" }, + { name = "tomlkit" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1d/f1/4aff125021a9c5e0183f2f55dd7d04b7256a0e1e10db50d537a7415d9c55/snowflake_connector_python-4.0.0.tar.gz", hash = "sha256:4b10a865c4a5e1fa60c365c7fe41e0433605e6e5edc824e8730a9038f330b3a6", size = 813937, upload-time = "2025-10-09T10:11:34.631Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/b0/462c0deee35d6d03d3d729b3f923615bae665beb7f9a94673a23a52080fe/snowflake_connector_python-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bfd3b8523d7adc830f99c5c4c635689ceca61700a05368d5bbb34c6811f2ec54", size = 1029568, upload-time = "2025-10-09T10:11:42.125Z" }, + { url = "https://files.pythonhosted.org/packages/ff/4b/bb3ae3f07e7927c8f16c4c0f1283d3c721978d16e8bf4193fc8e41025c1e/snowflake_connector_python-4.0.0-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:835161dd46ef8f5fc9d2f135ca654c2f3fbdf57b035d3e1980506aa8eac671dc", size = 1041337, upload-time = "2025-10-09T10:11:43.692Z" }, + { url = "https://files.pythonhosted.org/packages/9c/75/4bfac89f10c6dbb75e97adf1e217737fc599ebf964031c9298b6cbd807d0/snowflake_connector_python-4.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65e4e36dd1b0c7235d84cddef8a3c97c5ea0dc8fea85e31e45fc485000b77a83", size = 2699730, upload-time = "2025-10-09T10:11:25.295Z" }, + { url = "https://files.pythonhosted.org/packages/cd/78/0e916416c50909dbae511fe38b1e671a9efa62decdce51b174a0396804e4/snowflake_connector_python-4.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6132986d6965e4005b0167270612fbc7fa4bc4ef42726a40b85a8f57475a78d", size = 2731336, upload-time = "2025-10-09T10:11:27.028Z" }, + { url = "https://files.pythonhosted.org/packages/83/f0/3db8a2f3f5ee724d309c661af739a70d0643070b9b4597728151ef900f9b/snowflake_connector_python-4.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:a790f06808e4481c23cfed1396d2c9a786060ddd62408b1fda1a63e1e6bc4b07", size = 1176292, upload-time = "2025-10-09T10:11:54.956Z" }, + { url = "https://files.pythonhosted.org/packages/64/c0/10dfcce18514d711bf17d7766d24aedfc20d7a5aa0e8311c0d3068baf266/snowflake_connector_python-4.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4e8c3d2ea4055dd4aecc93514030341e300f557f2e86ca21eb47568c461a6f56", size = 1030702, upload-time = "2025-10-09T10:11:45.013Z" }, + { url = "https://files.pythonhosted.org/packages/16/c1/9d068375ccb341975eb95a87a99176b4b25bb7725e61c8ed62681f2d5123/snowflake_connector_python-4.0.0-cp313-cp313-macosx_11_0_x86_64.whl", hash = "sha256:1fea301e3d1e8022b9f2ff87dc3be139d5ed7be5e85fab8a6c59d400a02e6d58", size = 1042153, upload-time = "2025-10-09T10:11:46.309Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ae/f4da6b62e546f48885b63bc1884c935bc293e6da9605ddcd217e21307a63/snowflake_connector_python-4.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54e648bbd506a0f2f8076f9eafe231b2d4284b1a884528c3a0690391ab2bb54e", size = 2701637, upload-time = "2025-10-09T10:11:28.58Z" }, + { url = "https://files.pythonhosted.org/packages/88/bf/6cf92dbd1c6d95311894404e2c46db9a06ff6d37bea9a19e667d0bf26362/snowflake_connector_python-4.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f67d844241a6fed764a8f04d32c0273aedf9159d5162b764748526277c7f8831", size = 2733899, upload-time = "2025-10-09T10:11:30.186Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c8/7d9a41e1b10c0a2bae86241773a6b55c06e897c74b3cab14ec8315e16b34/snowflake_connector_python-4.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:cd23bff2abc74e34c6123a181c004ead9e6cc8ef2661250892afd64bad24533c", size = 1176311, upload-time = "2025-10-09T10:11:56.176Z" }, +] + +[[package]] +name = "snowpipe-streaming" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "msgspec" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/ea/83ff746c09bc03bd2f49b0435547d61189d2aee262d1cebb496debc48563/snowpipe_streaming-1.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:82d3870e92d6957161807376ebf2de289b7332c9fffce3490dcb039486a6d487", size = 9690846, upload-time = "2025-11-05T18:36:13.219Z" }, + { url = "https://files.pythonhosted.org/packages/e2/33/479a392be50e9e758528e9ab33972f4455184b37b23ffad9c2a89fd0d7d4/snowpipe_streaming-1.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8a1bbb94c6706d9d2a7aae416644c9a98b52e117c5b4420b875711201a4467e", size = 10736095, upload-time = "2025-11-05T18:36:16.08Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ec/ab32f82ec44b42279ab9ce456ad0678e5f689fb4bae0378c4c80fdd7b06b/snowpipe_streaming-1.1.0-cp39-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:eb674a9caf5746adbf13e972ea1bd8970902326457f9e4d8bd56b434035cf58e", size = 11006858, upload-time = "2025-11-05T18:36:18.406Z" }, + { url = "https://files.pythonhosted.org/packages/58/f0/97303f3d68ecb506c79c5af889f59b549eeb96e43ffa442b16062ba630ab/snowpipe_streaming-1.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:2b8c949e05e5d3883363d3b478e4083654f6f766c5b1998fc2daec552a304e3f", size = 8487628, upload-time = "2025-11-05T18:36:20.598Z" }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/bc/d59b5d97d27229b0e009bd9098cd81af71c2fa5549c580a0a67b9bed0496/sqlalchemy-2.0.43.tar.gz", hash = "sha256:788bfcef6787a7764169cfe9859fe425bf44559619e1d9f56f5bddf2ebf6f417", size = 9762949, upload-time = "2025-08-11T14:24:58.438Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/db/20c78f1081446095450bdc6ee6cc10045fce67a8e003a5876b6eaafc5cc4/sqlalchemy-2.0.43-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:20d81fc2736509d7a2bd33292e489b056cbae543661bb7de7ce9f1c0cd6e7f24", size = 2134891, upload-time = "2025-08-11T15:51:13.019Z" }, + { url = "https://files.pythonhosted.org/packages/45/0a/3d89034ae62b200b4396f0f95319f7d86e9945ee64d2343dcad857150fa2/sqlalchemy-2.0.43-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b9fc27650ff5a2c9d490c13c14906b918b0de1f8fcbb4c992712d8caf40e83", size = 2123061, upload-time = "2025-08-11T15:51:14.319Z" }, + { url = "https://files.pythonhosted.org/packages/cb/10/2711f7ff1805919221ad5bee205971254845c069ee2e7036847103ca1e4c/sqlalchemy-2.0.43-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6772e3ca8a43a65a37c88e2f3e2adfd511b0b1da37ef11ed78dea16aeae85bd9", size = 3320384, upload-time = "2025-08-11T15:52:35.088Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0e/3d155e264d2ed2778484006ef04647bc63f55b3e2d12e6a4f787747b5900/sqlalchemy-2.0.43-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a113da919c25f7f641ffbd07fbc9077abd4b3b75097c888ab818f962707eb48", size = 3329648, upload-time = "2025-08-11T15:56:34.153Z" }, + { url = "https://files.pythonhosted.org/packages/5b/81/635100fb19725c931622c673900da5efb1595c96ff5b441e07e3dd61f2be/sqlalchemy-2.0.43-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4286a1139f14b7d70141c67a8ae1582fc2b69105f1b09d9573494eb4bb4b2687", size = 3258030, upload-time = "2025-08-11T15:52:36.933Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ed/a99302716d62b4965fded12520c1cbb189f99b17a6d8cf77611d21442e47/sqlalchemy-2.0.43-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:529064085be2f4d8a6e5fab12d36ad44f1909a18848fcfbdb59cc6d4bbe48efe", size = 3294469, upload-time = "2025-08-11T15:56:35.553Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a2/3a11b06715149bf3310b55a98b5c1e84a42cfb949a7b800bc75cb4e33abc/sqlalchemy-2.0.43-cp312-cp312-win32.whl", hash = "sha256:b535d35dea8bbb8195e7e2b40059e2253acb2b7579b73c1b432a35363694641d", size = 2098906, upload-time = "2025-08-11T15:55:00.645Z" }, + { url = "https://files.pythonhosted.org/packages/bc/09/405c915a974814b90aa591280623adc6ad6b322f61fd5cff80aeaef216c9/sqlalchemy-2.0.43-cp312-cp312-win_amd64.whl", hash = "sha256:1c6d85327ca688dbae7e2b06d7d84cfe4f3fffa5b5f9e21bb6ce9d0e1a0e0e0a", size = 2126260, upload-time = "2025-08-11T15:55:02.965Z" }, + { url = "https://files.pythonhosted.org/packages/41/1c/a7260bd47a6fae7e03768bf66451437b36451143f36b285522b865987ced/sqlalchemy-2.0.43-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e7c08f57f75a2bb62d7ee80a89686a5e5669f199235c6d1dac75cd59374091c3", size = 2130598, upload-time = "2025-08-11T15:51:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/8e/84/8a337454e82388283830b3586ad7847aa9c76fdd4f1df09cdd1f94591873/sqlalchemy-2.0.43-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:14111d22c29efad445cd5021a70a8b42f7d9152d8ba7f73304c4d82460946aaa", size = 2118415, upload-time = "2025-08-11T15:51:17.256Z" }, + { url = "https://files.pythonhosted.org/packages/cf/ff/22ab2328148492c4d71899d62a0e65370ea66c877aea017a244a35733685/sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b27b56eb2f82653168cefe6cb8e970cdaf4f3a6cb2c5e3c3c1cf3158968ff9", size = 3248707, upload-time = "2025-08-11T15:52:38.444Z" }, + { url = "https://files.pythonhosted.org/packages/dc/29/11ae2c2b981de60187f7cbc84277d9d21f101093d1b2e945c63774477aba/sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c5a9da957c56e43d72126a3f5845603da00e0293720b03bde0aacffcf2dc04f", size = 3253602, upload-time = "2025-08-11T15:56:37.348Z" }, + { url = "https://files.pythonhosted.org/packages/b8/61/987b6c23b12c56d2be451bc70900f67dd7d989d52b1ee64f239cf19aec69/sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d79f9fdc9584ec83d1b3c75e9f4595c49017f5594fee1a2217117647225d738", size = 3183248, upload-time = "2025-08-11T15:52:39.865Z" }, + { url = "https://files.pythonhosted.org/packages/86/85/29d216002d4593c2ce1c0ec2cec46dda77bfbcd221e24caa6e85eff53d89/sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9df7126fd9db49e3a5a3999442cc67e9ee8971f3cb9644250107d7296cb2a164", size = 3219363, upload-time = "2025-08-11T15:56:39.11Z" }, + { url = "https://files.pythonhosted.org/packages/b6/e4/bd78b01919c524f190b4905d47e7630bf4130b9f48fd971ae1c6225b6f6a/sqlalchemy-2.0.43-cp313-cp313-win32.whl", hash = "sha256:7f1ac7828857fcedb0361b48b9ac4821469f7694089d15550bbcf9ab22564a1d", size = 2096718, upload-time = "2025-08-11T15:55:05.349Z" }, + { url = "https://files.pythonhosted.org/packages/ac/a5/ca2f07a2a201f9497de1928f787926613db6307992fe5cda97624eb07c2f/sqlalchemy-2.0.43-cp313-cp313-win_amd64.whl", hash = "sha256:971ba928fcde01869361f504fcff3b7143b47d30de188b11c6357c0505824197", size = 2123200, upload-time = "2025-08-11T15:55:07.932Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d9/13bdde6521f322861fab67473cec4b1cc8999f3871953531cf61945fad92/sqlalchemy-2.0.43-py3-none-any.whl", hash = "sha256:1681c21dd2ccee222c2fe0bef671d1aef7c504087c9c4e800371cfcc8ac966fc", size = 1924759, upload-time = "2025-08-11T15:39:53.024Z" }, +] + +[[package]] +name = "starlette" +version = "0.48.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/a5/d6f429d43394057b67a6b5bbe6eae2f77a6bf7459d961fdb224bf206eee6/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46", size = 2652949, upload-time = "2025-09-13T08:41:05.699Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/72/2db2f49247d0a18b4f1bb9a5a39a0162869acf235f3a96418363947b3d46/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659", size = 73736, upload-time = "2025-09-13T08:41:03.869Z" }, +] + +[[package]] +name = "strictyaml" +version = "1.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/08/efd28d49162ce89c2ad61a88bd80e11fb77bc9f6c145402589112d38f8af/strictyaml-1.7.3.tar.gz", hash = "sha256:22f854a5fcab42b5ddba8030a0e4be51ca89af0267961c8d6cfa86395586c407", size = 115206, upload-time = "2023-03-10T12:50:27.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/7c/a81ef5ef10978dd073a854e0fa93b5d8021d0594b639cc8f6453c3c78a1d/strictyaml-1.7.3-py3-none-any.whl", hash = "sha256:fb5c8a4edb43bebb765959e420f9b3978d7f1af88c80606c03fb420888f5d1c7", size = 123917, upload-time = "2023-03-10T12:50:17.242Z" }, +] + +[[package]] +name = "tenacity" +version = "9.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, +] + +[[package]] +name = "testcontainers" +version = "4.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docker" }, + { name = "python-dotenv" }, + { name = "typing-extensions" }, + { name = "urllib3" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/51/edac83edab339d8b4dce9a7b659163afb1ea7e011bfed1d5573d495a4485/testcontainers-4.13.2.tar.gz", hash = "sha256:2315f1e21b059427a9d11e8921f85fef322fbe0d50749bcca4eaa11271708ba4", size = 78692, upload-time = "2025-10-07T21:53:07.531Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/5e/73aa94770f1df0595364aed526f31d54440db5492911e2857318ed326e51/testcontainers-4.13.2-py3-none-any.whl", hash = "sha256:0209baf8f4274b568cde95bef2cadf7b1d33b375321f793790462e235cd684ee", size = 124771, upload-time = "2025-10-07T21:53:05.937Z" }, +] + +[[package]] +name = "tomlkit" +version = "0.13.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" }, +] + +[[package]] +name = "toolz" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790, upload-time = "2024-10-04T16:17:04.001Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383, upload-time = "2024-10-04T16:17:01.533Z" }, +] + +[[package]] +name = "typeguard" +version = "4.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/68/71c1a15b5f65f40e91b65da23b8224dad41349894535a97f63a52e462196/typeguard-4.4.4.tar.gz", hash = "sha256:3a7fd2dffb705d4d0efaed4306a704c89b9dee850b688f060a8b1615a79e5f74", size = 75203, upload-time = "2025-06-18T09:56:07.624Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/a9/e3aee762739c1d7528da1c3e06d518503f8b6c439c35549b53735ba52ead/typeguard-4.4.4-py3-none-any.whl", hash = "sha256:b5f562281b6bfa1f5492470464730ef001646128b180769880468bd84b68b09e", size = 34874, upload-time = "2025-06-18T09:56:05.999Z" }, +] + +[[package]] +name = "typer" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/ca/950278884e2ca20547ff3eb109478c6baf6b8cf219318e6bc4f666fad8e8/typer-0.19.2.tar.gz", hash = "sha256:9ad824308ded0ad06cc716434705f691d4ee0bfd0fb081839d2e426860e7fdca", size = 104755, upload-time = "2025-09-23T09:47:48.256Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/22/35617eee79080a5d071d0f14ad698d325ee6b3bf824fc0467c03b30e7fa8/typer-0.19.2-py3-none-any.whl", hash = "sha256:755e7e19670ffad8283db353267cb81ef252f595aa6834a0d1ca9312d9326cb9", size = 46748, upload-time = "2025-09-23T09:47:46.777Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.35.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/42/e0e305207bb88c6b8d3061399c6a961ffe5fbb7e2aa63c9234df7259e9cd/uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01", size = 78473, upload-time = "2025-06-28T16:15:46.058Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/e2/dc81b1bd1dcfe91735810265e9d26bc8ec5da45b4c0f6237e286819194c3/uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a", size = 66406, upload-time = "2025-06-28T16:15:44.816Z" }, +] + +[[package]] +name = "websockets" +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, + { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, + { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, + { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, + { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, + { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, + { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, + { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, + { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, +] + +[[package]] +name = "wrapt" +version = "1.17.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" }, + { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" }, + { url = "https://files.pythonhosted.org/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036, upload-time = "2025-08-12T05:52:34.784Z" }, + { url = "https://files.pythonhosted.org/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156, upload-time = "2025-08-12T05:52:13.599Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102, upload-time = "2025-08-12T05:52:14.56Z" }, + { url = "https://files.pythonhosted.org/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732, upload-time = "2025-08-12T05:52:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, + { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, + { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, + { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, + { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, + { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, + { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, + { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/cd864b2a14f20d14f4c496fab97802001560f9f41554eef6df201cd7f76c/wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39", size = 54132, upload-time = "2025-08-12T05:51:49.864Z" }, + { url = "https://files.pythonhosted.org/packages/d5/46/d011725b0c89e853dc44cceb738a307cde5d240d023d6d40a82d1b4e1182/wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235", size = 39091, upload-time = "2025-08-12T05:51:38.935Z" }, + { url = "https://files.pythonhosted.org/packages/2e/9e/3ad852d77c35aae7ddebdbc3b6d35ec8013af7d7dddad0ad911f3d891dae/wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c", size = 39172, upload-time = "2025-08-12T05:51:59.365Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f7/c983d2762bcce2326c317c26a6a1e7016f7eb039c27cdf5c4e30f4160f31/wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b", size = 87163, upload-time = "2025-08-12T05:52:40.965Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0f/f673f75d489c7f22d17fe0193e84b41540d962f75fce579cf6873167c29b/wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa", size = 87963, upload-time = "2025-08-12T05:52:20.326Z" }, + { url = "https://files.pythonhosted.org/packages/df/61/515ad6caca68995da2fac7a6af97faab8f78ebe3bf4f761e1b77efbc47b5/wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7", size = 86945, upload-time = "2025-08-12T05:52:21.581Z" }, + { url = "https://files.pythonhosted.org/packages/d3/bd/4e70162ce398462a467bc09e768bee112f1412e563620adc353de9055d33/wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4", size = 86857, upload-time = "2025-08-12T05:52:43.043Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b8/da8560695e9284810b8d3df8a19396a6e40e7518059584a1a394a2b35e0a/wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10", size = 37178, upload-time = "2025-08-12T05:53:12.605Z" }, + { url = "https://files.pythonhosted.org/packages/db/c8/b71eeb192c440d67a5a0449aaee2310a1a1e8eca41676046f99ed2487e9f/wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6", size = 39310, upload-time = "2025-08-12T05:53:11.106Z" }, + { url = "https://files.pythonhosted.org/packages/45/20/2cda20fd4865fa40f86f6c46ed37a2a8356a7a2fde0773269311f2af56c7/wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58", size = 37266, upload-time = "2025-08-12T05:52:56.531Z" }, + { url = "https://files.pythonhosted.org/packages/77/ed/dd5cf21aec36c80443c6f900449260b80e2a65cf963668eaef3b9accce36/wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a", size = 56544, upload-time = "2025-08-12T05:51:51.109Z" }, + { url = "https://files.pythonhosted.org/packages/8d/96/450c651cc753877ad100c7949ab4d2e2ecc4d97157e00fa8f45df682456a/wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067", size = 40283, upload-time = "2025-08-12T05:51:39.912Z" }, + { url = "https://files.pythonhosted.org/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454", size = 40366, upload-time = "2025-08-12T05:52:00.693Z" }, + { url = "https://files.pythonhosted.org/packages/64/0e/f4472f2fdde2d4617975144311f8800ef73677a159be7fe61fa50997d6c0/wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e", size = 108571, upload-time = "2025-08-12T05:52:44.521Z" }, + { url = "https://files.pythonhosted.org/packages/cc/01/9b85a99996b0a97c8a17484684f206cbb6ba73c1ce6890ac668bcf3838fb/wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f", size = 113094, upload-time = "2025-08-12T05:52:22.618Z" }, + { url = "https://files.pythonhosted.org/packages/25/02/78926c1efddcc7b3aa0bc3d6b33a822f7d898059f7cd9ace8c8318e559ef/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056", size = 110659, upload-time = "2025-08-12T05:52:24.057Z" }, + { url = "https://files.pythonhosted.org/packages/dc/ee/c414501ad518ac3e6fe184753632fe5e5ecacdcf0effc23f31c1e4f7bfcf/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804", size = 106946, upload-time = "2025-08-12T05:52:45.976Z" }, + { url = "https://files.pythonhosted.org/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717, upload-time = "2025-08-12T05:53:15.214Z" }, + { url = "https://files.pythonhosted.org/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334, upload-time = "2025-08-12T05:53:14.178Z" }, + { url = "https://files.pythonhosted.org/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471, upload-time = "2025-08-12T05:52:57.784Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, +] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, + { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, + { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, + { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, + { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, + { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, + { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, + { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, + { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, + { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, + { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, + { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, + { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, + { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, + { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, + { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, + { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, + { url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887, upload-time = "2025-09-14T22:17:54.198Z" }, + { url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658, upload-time = "2025-09-14T22:17:55.423Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849, upload-time = "2025-09-14T22:17:57.372Z" }, + { url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095, upload-time = "2025-09-14T22:17:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751, upload-time = "2025-09-14T22:18:01.618Z" }, + { url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818, upload-time = "2025-09-14T22:18:03.769Z" }, + { url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402, upload-time = "2025-09-14T22:18:05.954Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108, upload-time = "2025-09-14T22:18:07.68Z" }, + { url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248, upload-time = "2025-09-14T22:18:09.753Z" }, + { url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330, upload-time = "2025-09-14T22:18:11.966Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123, upload-time = "2025-09-14T22:18:13.907Z" }, + { url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591, upload-time = "2025-09-14T22:18:16.465Z" }, + { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" }, + { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" }, +]