diff --git a/.github/workflows/pr-preprod-tests.yaml b/.github/workflows/pr-preprod-tests.yaml index 61fa829d5b..7e4fec8710 100644 --- a/.github/workflows/pr-preprod-tests.yaml +++ b/.github/workflows/pr-preprod-tests.yaml @@ -24,13 +24,23 @@ jobs: run: | cd /home/integration/git/cardano-rosetta-java + # Fetch latest from remote + git fetch origin + # Clean up any existing PR branch and switch to main first git checkout main || git checkout develop - git branch -D pr-${{ github.event.pull_request.number }} 2>/dev/null || true + git pull origin main || git pull origin develop - # Fetch and checkout the PR - git fetch origin pull/${{ github.event.pull_request.number }}/head:pr-${{ github.event.pull_request.number }} - git checkout pr-${{ github.event.pull_request.number }} + # Checkout appropriate branch based on trigger type + if [ "${{ github.event_name }}" = "pull_request" ]; then + git branch -D pr-${{ github.event.pull_request.number }} 2>/dev/null || true + git fetch origin pull/${{ github.event.pull_request.number }}/head:pr-${{ github.event.pull_request.number }} + git checkout pr-${{ github.event.pull_request.number }} + else + # workflow_dispatch: checkout the selected branch and force sync with remote + git checkout ${{ github.ref_name }} + git reset --hard origin/${{ github.ref_name }} + fi - name: Stop current services run: | @@ -94,17 +104,24 @@ jobs: echo "Waiting for API to be ready..." # Wait for API to respond + API_STARTED=false for i in {1..60}; do if curl -sf -X POST http://localhost:8082/network/list \ -H 'Content-Type: application/json' \ -d '{}' > /dev/null 2>&1; then echo "API is responding" + API_STARTED=true break fi echo "Waiting for API to start... ($i/60)" sleep 10 done + if [ "$API_STARTED" != "true" ]; then + echo "❌ API failed to start after 10 minutes" + exit 1 + fi + # Check sync status echo "Checking sync status..." while true; do @@ -150,6 +167,9 @@ jobs: # Copy to tests directory cp .env.test tests/data-endpoints/.env + - name: Clean previous Allure results + run: rm -rf /home/integration/git/cardano-rosetta-java/tests/data-endpoints/allure-results/* + - name: Run smoke tests (validate test data) id: smoke_tests run: | @@ -196,23 +216,22 @@ jobs: ROSETTA_URL: http://localhost:8082 CARDANO_NETWORK: preprod - - name: Run construction API tests - id: construction_test + - name: Run golden example tests + id: golden_tests run: | export PATH="$HOME/.local/bin:$PATH" cd /home/integration/git/cardano-rosetta-java/tests/integration - # Run construction API snapshot tests - uv run test_construction_api.py \ - -v || CONSTRUCTION_RESULT=$? + # Run golden example tests (construction + data endpoints) + uv run test_golden_examples.py \ + -v || GOLDEN_RESULT=$? # Output test result - echo "construction_result=${CONSTRUCTION_RESULT:-0}" >> $GITHUB_OUTPUT + echo "golden_result=${GOLDEN_RESULT:-0}" >> $GITHUB_OUTPUT - # Don't fail the whole job if construction tests fail - # These are informational for now - exit 0 + # Fail if golden example tests failed + exit ${GOLDEN_RESULT:-0} env: ROSETTA_URL: http://localhost:8082 CARDANO_NETWORK: preprod @@ -247,22 +266,43 @@ jobs: user_name: 'github-actions[bot]' user_email: '41898282+github-actions[bot]@users.noreply.github.com' + - name: Cleanup gh-pages temp directories + if: always() + run: rm -rf ~/actions_github_pages_* + - name: Comment PR with results - if: always() && github.event_name == 'pull_request' && steps.test.outcome != 'skipped' + if: always() && github.event_name == 'pull_request' uses: actions/github-script@v6 with: script: | const prNumber = context.issue.number; - const testResult = '${{ steps.test.outputs.test_result }}'; - const emoji = testResult === '0' ? '✅' : '❌'; - const status = testResult === '0' ? 'PASSED' : 'FAILED'; + + // Check if earlier steps failed (deployment, sync, etc.) + const testsSkipped = '${{ steps.test.outcome }}' === 'skipped'; + + let emoji, status; + if (testsSkipped) { + emoji = '💥'; + status = 'DEPLOYMENT FAILED'; + } else { + // Check all three test outputs + const smokeResult = '${{ steps.smoke_tests.outputs.smoke_result }}'; + const testResult = '${{ steps.test.outputs.test_result }}'; + const goldenResult = '${{ steps.golden_tests.outputs.golden_result }}'; + + const allPassed = smokeResult === '0' && testResult === '0' && goldenResult === '0'; + emoji = allPassed ? '✅' : '❌'; + status = allPassed ? 'PASSED' : 'FAILED'; + } // Build comment body let comment = `## ${emoji} Preprod Tests: ${status}\n\n`; - // Add report link - const reportUrl = `https://cardano-foundation.github.io/cardano-rosetta-java/test-reports/pr-${prNumber}/`; - comment += `📊 **[View Detailed Test Report](${reportUrl})**\n\n`; + // Add report link (only if tests actually ran) + if (!testsSkipped) { + const reportUrl = `https://cardano-foundation.github.io/cardano-rosetta-java/test-reports/pr-${prNumber}/`; + comment += `📊 **[View Detailed Test Report](${reportUrl})**\n\n`; + } comment += `🔗 [Action Run #${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})\n\n`; comment += `_Tests run against preprod network with live blockchain data_`; diff --git a/.gitignore b/.gitignore index 7499c9a66d..d694ec1251 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ hs_err_pid* target settings.xml .env* +!.env.example /data/ /node/ diff --git a/load-tests/README.MD b/load-tests/README.MD index ac5c62727c..143cfd7572 100644 --- a/load-tests/README.MD +++ b/load-tests/README.MD @@ -78,6 +78,7 @@ usage: stability_test.py [-h] [--url BASE_URL] [--csv CSV_FILE] [--concurrency CONCURRENCIES] [--duration TEST_DURATION] [--sla SLA_THRESHOLD] [--error-threshold ERROR_THRESHOLD] [--skip-header] [-v] [--cooldown COOLDOWN] + [--network NETWORK] [--endpoints SELECTED_ENDPOINTS] [--list-endpoints] Cardano Rosetta API Stability Testing Tool @@ -102,6 +103,7 @@ options: --skip-header Skip the header row in the CSV file (default: False) -v, --verbose Enable verbose output (default: False) --cooldown COOLDOWN Cooldown period in seconds between endpoint tests (default: 60) + --network NETWORK Network identifier for API requests: mainnet or preprod (default: mainnet) --endpoints SELECTED_ENDPOINTS Comma-separated list of endpoint names or paths to test (e.g. "Network Status,Block" or "/account/balance,/block"). If not specified, all endpoints will be tested. @@ -140,10 +142,22 @@ Test only specific endpoints by path: ./load-tests/stability_test.py --endpoints "/network/status,/block,/account/balance" ``` -Test only search/transactions endpoint with stake address data: +Test search/transactions by hash lookup: ```bash -./load-tests/stability_test.py --endpoints "/search/transactions" --csv load-tests/data/mainnet-data-stake-address.csv +./load-tests/stability_test.py --endpoints "Search Transactions by Hash" +``` + +Test search/transactions by address (more resource-intensive): + +```bash +./load-tests/stability_test.py --endpoints "Search Transactions by Address" --csv load-tests/data/mainnet-data.csv +``` + +Test on preprod network: + +```bash +./load-tests/stability_test.py --network preprod --url http://127.0.0.1:8082 --csv data/preprod-data.csv ``` List all available endpoints without running tests: @@ -164,6 +178,62 @@ Test with custom SLA and error thresholds: ./load-tests/stability_test.py --sla 500 --error-threshold 0.5 ``` +## Test Data + +### CSV Format Requirements + +Each CSV row must have 6 fields with specific associations: + +``` +address,block_index,block_hash,transaction_size,relative_ttl,transaction_hash +``` + +**Critical Data Associations (Implicit Rules):** + +1. **Block Consistency**: The `block_hash` MUST be the hash of the block at `block_index` +2. **Transaction in Block**: The `transaction_hash` MUST exist in the specified block (`block_hash`) +3. **Address in Transaction**: The `address` MUST be involved in the transaction (appear in operations as input/output) +4. **Transaction Size**: The `transaction_size` MUST match the actual size of the transaction in bytes +5. **Valid Address**: The `address` MUST have a balance and UTXO history (for account endpoints) +6. **TTL Value**: The `relative_ttl` is used by construction/metadata endpoint (1000 is standard) + +These associations ensure all 8 endpoints can successfully use the same data row: +- Network Status: No specific data needed +- Account Balance/Coins: Requires valid address with balance +- Block: Requires valid block_index and block_hash +- Block Transaction: Requires transaction in specified block +- Search by Hash: Requires valid transaction_hash +- Search by Address: Requires address involved in transactions +- Construction Metadata: Requires transaction_size and relative_ttl + +### Available Data Files + +The `data/` directory contains pre-validated CSV files for different networks: + +### Mainnet Data (`mainnet-data.csv`) +- **Block**: 11573705 +- **Transaction**: 3a954835b69ca01ff9cf3b30ce385d5d9ef0cea502bd0f2ad156684dfbaf325a +- **Address**: addr1qxw5ly68dml8ceg7eawa7we8pjw8j8hn74n2djt2upmnq9th42p6lrke4yj3e0xqg3sdqm6lzksa53wd2550vrpkedks4fttnm + +### Preprod Data (`preprod-data.csv`) +- **Block**: 4070700 +- **Transaction**: bf540a825d5d40af7435801ce6adcac010f3f9f29ae102aee8cff8007f68c3d4 +- **Address**: addr_test1wzn5ee2qaqvly3hx7e0nk3vhm240n5muq3plhjcnvx9ppjgf62u6a + +All data has been validated to work with all 8 stability test endpoints, with proper associations between blocks, transactions, and addresses. + +## Endpoint Details + +### Search Transactions Endpoints + +The stability test includes two variants of the `/search/transactions` endpoint: + +1. **Search Transactions by Hash**: Queries transactions using `transaction_identifier`. This is a fast, direct lookup by transaction hash. + +2. **Search Transactions by Address**: Queries transactions using `account_identifier` with an address. This is more resource-intensive as it requires scanning transaction operations to find all transactions involving the specified address. + +Both endpoints use the same API path (`/search/transactions`) but with different query parameters, allowing independent performance testing of each query pattern. + ## Output The script creates a timestamped directory containing: diff --git a/load-tests/data/preprod-data.csv b/load-tests/data/preprod-data.csv new file mode 100644 index 0000000000..a6c8a3a293 --- /dev/null +++ b/load-tests/data/preprod-data.csv @@ -0,0 +1,2 @@ +address,block_index,block_hash,transaction_size,relative_ttl,transaction_hash +addr_test1wzn5ee2qaqvly3hx7e0nk3vhm240n5muq3plhjcnvx9ppjgf62u6a,4070700,6b1b29d0533a86443140a88d3758f26fa9d4a8954363e78818b3235126ba933b,683,1000,bf540a825d5d40af7435801ce6adcac010f3f9f29ae102aee8cff8007f68c3d4 diff --git a/load-tests/stability_test.py b/load-tests/stability_test.py index 6d961f5e9b..b28d2b8e46 100755 --- a/load-tests/stability_test.py +++ b/load-tests/stability_test.py @@ -73,7 +73,10 @@ def parse_args(): help='Cooldown period in seconds between endpoint tests') parser.add_argument('--max-retries', dest='max_retries', type=int, default=2, help='Maximum number of retries when an ab command fails') - + parser.add_argument('--network', dest='network', default="mainnet", + choices=['mainnet', 'preprod'], + help='Network identifier for API requests') + # Endpoint selection parser.add_argument('--endpoints', dest='selected_endpoints', type=str, help='Comma-separated list of endpoint names or paths to test (e.g. "Network Status,Block" or "/account/balance,/block"). If not specified, all endpoints will be tested.') @@ -104,6 +107,7 @@ def parse_args(): VERBOSE = args.verbose COOLDOWN_PERIOD = args.cooldown MAX_RETRIES = args.max_retries +NETWORK_ID = args.network # Global logger variable logger = None @@ -200,7 +204,6 @@ def parse_ab_output(ab_stdout: str): requests_per_sec = 0.0 mean_time = 0.0 non_2xx_responses = 0 - failed_requests = 0 # Parse each metric for line in ab_stdout.splitlines(): @@ -234,13 +237,8 @@ def parse_ab_output(ab_stdout: str): parts = line.split() if len(parts) >= 3: non_2xx_responses = int(parts[2]) - # Parse Failed requests - elif "Failed requests:" in line: - parts = line.split() - if len(parts) >= 3: - failed_requests = int(parts[2]) - return p95, p99, complete_requests, requests_per_sec, mean_time, non_2xx_responses, failed_requests + return p95, p99, complete_requests, requests_per_sec, mean_time, non_2xx_responses ############################################################################### # PAYLOAD GENERATORS @@ -252,14 +250,14 @@ def payload_network_status(*_): """ /network/status does not really need CSV data. """ - return dedent("""\ - { - "network_identifier": { + return dedent(f"""\ + {{ + "network_identifier": {{ "blockchain": "cardano", - "network": "mainnet" - }, - "metadata": {} - } + "network": "{NETWORK_ID}" + }}, + "metadata": {{}} + }} """) def payload_account_balance(address, *_): @@ -270,7 +268,7 @@ def payload_account_balance(address, *_): {{ "network_identifier": {{ "blockchain": "cardano", - "network": "mainnet" + "network": "{NETWORK_ID}" }}, "account_identifier": {{ "address": "{address}" @@ -286,7 +284,7 @@ def payload_account_coins(address, *_): {{ "network_identifier": {{ "blockchain": "cardano", - "network": "mainnet" + "network": "{NETWORK_ID}" }}, "account_identifier": {{ "address": "{address}" @@ -303,7 +301,7 @@ def payload_block(_addr, block_index, block_hash, *_): {{ "network_identifier": {{ "blockchain": "cardano", - "network": "mainnet" + "network": "{NETWORK_ID}" }}, "block_identifier": {{ "index": {block_index}, @@ -320,7 +318,7 @@ def payload_block_transaction(_addr, block_index, block_hash, _tx_size, _ttl, tr {{ "network_identifier": {{ "blockchain": "cardano", - "network": "mainnet" + "network": "{NETWORK_ID}" }}, "block_identifier": {{ "index": {block_index}, @@ -332,7 +330,7 @@ def payload_block_transaction(_addr, block_index, block_hash, _tx_size, _ttl, tr }} """) -def payload_search_transactions(_addr, _block_index, _block_hash, _tx_size, _ttl, transaction_hash): +def payload_search_transactions_by_hash(_addr, _block_index, _block_hash, _tx_size, _ttl, transaction_hash): """ /search/transactions requires transaction_hash. """ @@ -340,7 +338,7 @@ def payload_search_transactions(_addr, _block_index, _block_hash, _tx_size, _ttl {{ "network_identifier": {{ "blockchain": "cardano", - "network": "mainnet" + "network": "{NETWORK_ID}" }}, "transaction_identifier": {{ "hash": "{transaction_hash}" @@ -348,6 +346,22 @@ def payload_search_transactions(_addr, _block_index, _block_hash, _tx_size, _ttl }} """) +def payload_search_transactions_by_address(address, *_): + """ + /search/transactions with account_identifier (address-based query). + """ + return dedent(f"""\ + {{ + "network_identifier": {{ + "blockchain": "cardano", + "network": "{NETWORK_ID}" + }}, + "account_identifier": {{ + "address": "{address}" + }} + }} + """) + def payload_construction_metadata(_addr, _block_index, _block_hash, transaction_size, relative_ttl, _tx_hash): """ /construction/metadata requires transaction_size, relative_ttl @@ -356,7 +370,7 @@ def payload_construction_metadata(_addr, _block_index, _block_hash, transaction_ {{ "network_identifier": {{ "blockchain": "cardano", - "network": "mainnet" + "network": "{NETWORK_ID}" }}, "options": {{ "transaction_size": {transaction_size}, @@ -368,15 +382,16 @@ def payload_construction_metadata(_addr, _block_index, _block_hash, transaction_ ############################################################################### # ENDPOINT DEFINITION ############################################################################### -# We'll define 7 endpoints with: (Name, Path, Payload Generator Function) +# We'll define 8 endpoints with: (Name, Path, Payload Generator Function) ENDPOINTS = [ - ("Network Status", "/network/status", payload_network_status), - ("Account Balance", "/account/balance", payload_account_balance), - ("Account Coins", "/account/coins", payload_account_coins), - ("Block", "/block", payload_block), - ("Block Transaction", "/block/transaction", payload_block_transaction), - ("Search Transactions", "/search/transactions", payload_search_transactions), - ("Construction Metadata","/construction/metadata", payload_construction_metadata), + ("Network Status", "/network/status", payload_network_status), + ("Account Balance", "/account/balance", payload_account_balance), + ("Account Coins", "/account/coins", payload_account_coins), + ("Block", "/block", payload_block), + ("Block Transaction", "/block/transaction", payload_block_transaction), + ("Search Transactions by Hash", "/search/transactions", payload_search_transactions_by_hash), + ("Search Transactions by Address", "/search/transactions", payload_search_transactions_by_address), + ("Construction Metadata", "/construction/metadata", payload_construction_metadata), ] ############################################################################### @@ -493,7 +508,13 @@ def test_endpoint(endpoint_name, endpoint_path, payload_func, csv_row): # Example CSV columns: # address, block_index, block_hash, transaction_size, relative_ttl, transaction_hash # - # Adjust if your CSV has different columns or order. + # Validate CSV structure + if len(csv_row) != 6: + logger.error(f"Invalid CSV format for endpoint {endpoint_name}.") + logger.error(f"Expected 6 columns (address, block_index, block_hash, transaction_size, relative_ttl, transaction_hash)") + logger.error(f"Got {len(csv_row)} columns: {csv_row}") + sys.exit(1) + address, block_index, block_hash, transaction_size, relative_ttl, transaction_hash = csv_row # Generate JSON payload @@ -546,9 +567,13 @@ def test_endpoint(endpoint_name, endpoint_path, payload_func, csv_row): if VERBOSE: # Format each line with box borders if line_stripped: - # Fixed width approach + # Truncate long lines to fit box width + max_content_width = box_width - 4 # 2 for borders, 2 for padding + if len(line_stripped) > max_content_width: + line_stripped = line_stripped[:max_content_width - 3] + "..." content = "│ " + line_stripped - logger.debug(content + " " * (box_width - len(content) - 1) + "│") + padding = " " * (box_width - len(content) - 1) + logger.debug(content + padding + "│") else: logger.debug("│" + " " * (box_width - 2) + "│") proc.stdout.close() @@ -615,7 +640,7 @@ def test_endpoint(endpoint_name, endpoint_path, payload_func, csv_row): break # Parse p95, p99 and additional metrics from the captured stdout - p95, p99, complete_requests, requests_per_sec, mean_time, non_2xx_responses, failed_requests = parse_ab_output(ab_output) + p95, p99, complete_requests, requests_per_sec, mean_time, non_2xx_responses = parse_ab_output(ab_output) # Calculate error rate as a percentage error_rate = 0.0 @@ -748,8 +773,9 @@ def main(): logger.debug(f"Data row: {', '.join(rows[0]) if rows else 'No data available'}") logger.debug(f"{'-' * 80}") - # For demonstration, pick the *first* row only. - # If you want to test multiple rows, you can loop here or adapt logic. + # Use only the first CSV row for consistency across all endpoints and concurrency levels. + # This ensures that performance comparisons are based on the same data characteristics. + # All endpoints will be tested with identical input data to measure their relative performance. if not rows: # Use logger.error and exit logger.error("No CSV data after skipping header.") @@ -911,8 +937,8 @@ def main(): logger.warning("=" * 80) current_endpoint = None - if 'ep_name' in locals() and 'c' in locals(): - current_endpoint = f"{ep_name} at concurrency level {c}" + if 'ep_name' in locals(): + current_endpoint = ep_name if current_endpoint: logger.warning(f"Test was interrupted while testing: {current_endpoint}") diff --git a/tests/data-endpoints/test_account_endpoints.py b/tests/data-endpoints/test_account_endpoints.py index 8da5e582a6..9db8ba381b 100644 --- a/tests/data-endpoints/test_account_endpoints.py +++ b/tests/data-endpoints/test_account_endpoints.py @@ -183,6 +183,49 @@ def test_invalid_address_returns_error(self, client, network): assert response.status_code == 500 +@allure.feature("Account") +@allure.story("Native Asset Metadata") +class TestNativeAssetMetadata: + """Validate that native assets always include required metadata fields (API contract).""" + + def test_native_assets_always_have_policy_id(self, client, network, network_data): + """Verify policyId is always present for native assets.""" + # Use shelley_base address which is known to have native assets + address = network_data["addresses"]["shelley_base"] + + response = client.account_balance( + network=network, + account_identifier={"address": address} + ) + assert response.status_code == 200 + + balances = response.json()["balances"] + + # Find native assets (non-ADA balances) + native_assets = [b for b in balances if b["currency"]["symbol"] != "ADA"] + + assert len(native_assets) > 0, ( + "Test requires address with native assets for validation" + ) + + # Validate policyId is present for all native assets + for balance in native_assets: + currency = balance["currency"] + metadata = currency.get("metadata", {}) + + assert "policyId" in metadata, ( + f"Native asset {currency.get('symbol')} missing required metadata.policyId field. " + f"This is an API contract violation - all native assets must expose policyId." + ) + + # policyId should be valid hex (56 chars = 28 bytes) + policy_id = metadata["policyId"] + assert len(policy_id) == 56, f"policyId must be 56 hex chars, got {len(policy_id)}" + assert all(c in "0123456789abcdef" for c in policy_id.lower()), ( + "policyId must be valid hex string" + ) + + @allure.feature("Account") @allure.story("Account Coins") class TestAccountCoins: diff --git a/tests/data-endpoints/test_token_registry.py b/tests/data-endpoints/test_token_registry.py index fb6db283b1..dd21694e5b 100644 --- a/tests/data-endpoints/test_token_registry.py +++ b/tests/data-endpoints/test_token_registry.py @@ -203,25 +203,6 @@ def _search_operations_for_token(client, network: str, token: Dict) -> List[Tupl return matches -@allure.feature("Token Registry") -@allure.story("v1.4.0 Feature - policyId") -class TestPolicyIdMetadata: - """Verify policy identifiers are exposed for configured tokens.""" - - @pytest.mark.pr - def test_tokens_expose_policy_id(self, client, network, tokens_config, has_token_registry): - assert has_token_registry, "Token registry must be enabled for this test" - - for token in tokens_config: - currency, metadata = _fetch_token_from_account(client, network, token) - - assert currency is not None, f"Token {token['ticker']} not found" - assert "policyId" in metadata, "Missing policyId in enriched metadata" - if token.get("subject"): - symbol = currency.get("symbol", "") - assert metadata.get("policyId") + symbol == token["subject"] - - @pytest.mark.smoke @pytest.mark.requires_token_registry @allure.feature("Smoke Tests") diff --git a/tests/integration/golden_examples/rosetta_java/construction/combine/simple_transactions/10_inputs_10_outputs_with_byron_addresses.json b/tests/integration/golden_examples/rosetta_java/construction/combine/simple_transactions/10_inputs_10_outputs_with_byron_addresses.json index 8f3a04e6e5..22da0f8eaf 100644 --- a/tests/integration/golden_examples/rosetta_java/construction/combine/simple_transactions/10_inputs_10_outputs_with_byron_addresses.json +++ b/tests/integration/golden_examples/rosetta_java/construction/combine/simple_transactions/10_inputs_10_outputs_with_byron_addresses.json @@ -1,6 +1,7 @@ { "test_name": "10 inputs → 10 outputs with byron addresses combine", "description": "Combine test for Payloads for 10 inputs → 10 outputs with byron addresses", + "skip_reason": "Byron address data missing, requires yaci-store upgrade and re-indexing (#585)", "request_body": { "network_identifier": { "blockchain": "cardano", diff --git a/tests/integration/golden_examples/rosetta_java/construction/hash/simple_transactions/10_inputs_10_outputs_with_byron_addresses.json b/tests/integration/golden_examples/rosetta_java/construction/hash/simple_transactions/10_inputs_10_outputs_with_byron_addresses.json index 25b8fe7b7b..76ac7f5ff6 100644 --- a/tests/integration/golden_examples/rosetta_java/construction/hash/simple_transactions/10_inputs_10_outputs_with_byron_addresses.json +++ b/tests/integration/golden_examples/rosetta_java/construction/hash/simple_transactions/10_inputs_10_outputs_with_byron_addresses.json @@ -1,6 +1,7 @@ { "test_name": "10 inputs → 10 outputs with byron addresses hash", "description": "Hash test for Payloads for 10 inputs → 10 outputs with byron addresses (skipped due to combine error)", + "skip_reason": "Byron address data missing, requires yaci-store upgrade and re-indexing (#585)", "request_body": { "network_identifier": { "blockchain": "cardano", diff --git a/tests/integration/golden_examples/rosetta_java/construction/parse/native_assets/multiple_assets_different_policies.json b/tests/integration/golden_examples/rosetta_java/construction/parse/native_assets/multiple_assets_different_policies.json index 485a80a338..3bfb5312dc 100644 --- a/tests/integration/golden_examples/rosetta_java/construction/parse/native_assets/multiple_assets_different_policies.json +++ b/tests/integration/golden_examples/rosetta_java/construction/parse/native_assets/multiple_assets_different_policies.json @@ -1,6 +1,7 @@ { "test_name": "multiple assets different policies", "description": "Parse for multiple assets different policies", + "skip_reason": "Multiple native assets with different policy IDs parsing failure (#582)", "request_body": { "network_identifier": { "blockchain": "cardano", diff --git a/tests/integration/golden_examples/rosetta_java/construction/preprocess/drep_vote_delegation/cip129_prefix_only_should_work.json b/tests/integration/golden_examples/rosetta_java/construction/preprocess/drep_vote_delegation/cip129_prefix_only_should_work.json index 142fe00d17..eee7408d98 100644 --- a/tests/integration/golden_examples/rosetta_java/construction/preprocess/drep_vote_delegation/cip129_prefix_only_should_work.json +++ b/tests/integration/golden_examples/rosetta_java/construction/preprocess/drep_vote_delegation/cip129_prefix_only_should_work.json @@ -1,6 +1,7 @@ { "test_name": "(SKIP) CIP-129 prefix-only should infer type", "description": "SKIP: CIP-129 prefix should make type field optional. Currently not supported - needs investigation", + "skip_reason": "CIP-129 prefix should make type field optional, not yet implemented (#657)", "request_body": { "network_identifier": { "blockchain": "cardano", diff --git a/tests/integration/golden_examples/rosetta_java/data/search/chronological_order_descending.json b/tests/integration/golden_examples/rosetta_java/data/search/chronological_order_descending.json new file mode 100644 index 0000000000..04a93bc094 --- /dev/null +++ b/tests/integration/golden_examples/rosetta_java/data/search/chronological_order_descending.json @@ -0,0 +1,1349 @@ +{ + "test_name": "search transactions chronological order descending", + "description": "Verifies that /search/transactions returns transactions in descending chronological order (newest first). Block indices should be: 3685493, 3685493, 3685492, 3685492, 3685492. Within-block ordering: transactions in the same block should be in reverse tx index order (d9b6..., bc50..., 0839... for block 3685492)", + "skip_reason": "Within-block ordering bug not fixed yet, planned for v2.1.x (#534)", + "endpoint": "/search/transactions", + "request_body": { + "network_identifier": { + "blockchain": "cardano", + "network": "{{networkId}}" + }, + "limit": 5, + "max_block": 3685500 + }, + "expected_response": { + "transactions": [ + { + "block_identifier": { + "index": 3685493, + "hash": "ec371603d3d9018df7ca768ff008d01d7f6d57c81300c5bd4b36a995ebf84f5d" + }, + "transaction": { + "transaction_identifier": { + "hash": "8eec1abae550114cf881c5972c4cfa0a68bde41ea99a461f16777b98c9ee57e9" + }, + "operations": [ + { + "operation_identifier": { + "index": 0 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1wqd2qdzhh3x280q6erdksyku6k3eknrqsmrpkjnn6hsvjegk9gghn" + }, + "amount": { + "value": "-2000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "e1bb21018a18b47a54ecf562d58a3d54cd01016a86a4d19b0fbed24e6883ddcc:0" + }, + "coin_action": "coin_spent" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "657991fcca11e70169ba87ef626d2a3a5bd35faa32a5946b8689a342", + "tokens": [ + { + "value": "-1", + "currency": { + "symbol": "4e6f646546656564", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 1 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1vr93fxkq3jnp5w3m7gtkpasm2z729s3532jfay4n76455fszx3eq2" + }, + "amount": { + "value": "-11594345", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "0986598d8aaa10f3b2bd47d5a006cc76a6063f05e9cfb66e1e02fb0159674a03:2" + }, + "coin_action": "coin_spent" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "698a6ea0ca99f315034072af31eaac6ec11fe8558d3f48e9775aab9d", + "tokens": [ + { + "value": "-1205730", + "currency": { + "symbol": "7444524950", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 2 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1vr93fxkq3jnp5w3m7gtkpasm2z729s3532jfay4n76455fszx3eq2" + }, + "amount": { + "value": "-8510450", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "c2ac7bc758e2dba4e138ed9751782725c411b14a54f27f9f45d68cc348fdb92f:2" + }, + "coin_action": "coin_spent" + } + }, + { + "operation_identifier": { + "index": 3, + "network_index": 0 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1wqd2qdzhh3x280q6erdksyku6k3eknrqsmrpkjnn6hsvjegk9gghn" + }, + "amount": { + "value": "2000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "8eec1abae550114cf881c5972c4cfa0a68bde41ea99a461f16777b98c9ee57e9:0" + }, + "coin_action": "coin_created" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "657991fcca11e70169ba87ef626d2a3a5bd35faa32a5946b8689a342", + "tokens": [ + { + "value": "1", + "currency": { + "symbol": "4e6f646546656564", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 4, + "network_index": 2 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1vr93fxkq3jnp5w3m7gtkpasm2z729s3532jfay4n76455fszx3eq2" + }, + "amount": { + "value": "10610694", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "8eec1abae550114cf881c5972c4cfa0a68bde41ea99a461f16777b98c9ee57e9:2" + }, + "coin_action": "coin_created" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "698a6ea0ca99f315034072af31eaac6ec11fe8558d3f48e9775aab9d", + "tokens": [ + { + "value": "1205730", + "currency": { + "symbol": "7444524950", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 5, + "network_index": 1 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1vr93fxkq3jnp5w3m7gtkpasm2z729s3532jfay4n76455fszx3eq2" + }, + "amount": { + "value": "9000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "8eec1abae550114cf881c5972c4cfa0a68bde41ea99a461f16777b98c9ee57e9:1" + }, + "coin_action": "coin_created" + } + } + ], + "metadata": { + "size": 587, + "scriptSize": 0 + } + } + }, + { + "block_identifier": { + "index": 3685493, + "hash": "ec371603d3d9018df7ca768ff008d01d7f6d57c81300c5bd4b36a995ebf84f5d" + }, + "transaction": { + "transaction_identifier": { + "hash": "2125c27b7faad8007b8003ba6fd2c2986f8d7689d1366f92007be30bc27da1c5" + }, + "operations": [ + { + "operation_identifier": { + "index": 0 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1wzk66pus8w3g08v8uzklz8jyu7u255cu329tj200xwfr59s4p9qtd" + }, + "amount": { + "value": "-3000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "bc9fd87b480a157558a782909984b7b5cba6425c1646da5ca8b97b38668c410a:0" + }, + "coin_action": "coin_spent" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "33420b5518842c1d2d2ada6fc1b49d82b62c42d822345180a20e4e5f", + "tokens": [ + { + "value": "-1", + "currency": { + "symbol": "4167675374617465", + "decimals": 0 + } + } + ] + }, + { + "policyId": "c6f192a236596e2bbaac5900d67e9700dec7c77d9da626c98e0ab2ac", + "tokens": [ + { + "value": "-9999278068", + "currency": { + "symbol": "5061796d656e74546f6b656e", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 1 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1wzk66pus8w3g08v8uzklz8jyu7u255cu329tj200xwfr59s4p9qtd" + }, + "amount": { + "value": "-2000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "bc9fd87b480a157558a782909984b7b5cba6425c1646da5ca8b97b38668c410a:1" + }, + "coin_action": "coin_spent" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "33420b5518842c1d2d2ada6fc1b49d82b62c42d822345180a20e4e5f", + "tokens": [ + { + "value": "-1", + "currency": { + "symbol": "4f7261636c6546656564", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 2 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1wzk66pus8w3g08v8uzklz8jyu7u255cu329tj200xwfr59s4p9qtd" + }, + "amount": { + "value": "-3000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "bc9fd87b480a157558a782909984b7b5cba6425c1646da5ca8b97b38668c410a:2" + }, + "coin_action": "coin_spent" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "33420b5518842c1d2d2ada6fc1b49d82b62c42d822345180a20e4e5f", + "tokens": [ + { + "value": "-1", + "currency": { + "symbol": "526577617264", + "decimals": 0 + } + } + ] + }, + { + "policyId": "c6f192a236596e2bbaac5900d67e9700dec7c77d9da626c98e0ab2ac", + "tokens": [ + { + "value": "-722932", + "currency": { + "symbol": "5061796d656e74546f6b656e", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 3 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1vzkswm5qxd50an9xmfulygxykkk23h8ykfcqk5ya6fwuwaspgd4wr" + }, + "amount": { + "value": "-11169281", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "edc9bfcf2c3ee1e3687bf0e4f18e67a76800c8036863ecf511d97d9066fbc447:2" + }, + "coin_action": "coin_spent" + } + }, + { + "operation_identifier": { + "index": 4, + "network_index": 0 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + }, + { + "index": 3 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1wzk66pus8w3g08v8uzklz8jyu7u255cu329tj200xwfr59s4p9qtd" + }, + "amount": { + "value": "3000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "2125c27b7faad8007b8003ba6fd2c2986f8d7689d1366f92007be30bc27da1c5:0" + }, + "coin_action": "coin_created" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "33420b5518842c1d2d2ada6fc1b49d82b62c42d822345180a20e4e5f", + "tokens": [ + { + "value": "1", + "currency": { + "symbol": "4167675374617465", + "decimals": 0 + } + } + ] + }, + { + "policyId": "c6f192a236596e2bbaac5900d67e9700dec7c77d9da626c98e0ab2ac", + "tokens": [ + { + "value": "9999277955", + "currency": { + "symbol": "5061796d656e74546f6b656e", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 5, + "network_index": 1 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + }, + { + "index": 3 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1wzk66pus8w3g08v8uzklz8jyu7u255cu329tj200xwfr59s4p9qtd" + }, + "amount": { + "value": "2000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "2125c27b7faad8007b8003ba6fd2c2986f8d7689d1366f92007be30bc27da1c5:1" + }, + "coin_action": "coin_created" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "33420b5518842c1d2d2ada6fc1b49d82b62c42d822345180a20e4e5f", + "tokens": [ + { + "value": "1", + "currency": { + "symbol": "4f7261636c6546656564", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 6, + "network_index": 2 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + }, + { + "index": 3 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1wzk66pus8w3g08v8uzklz8jyu7u255cu329tj200xwfr59s4p9qtd" + }, + "amount": { + "value": "3000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "2125c27b7faad8007b8003ba6fd2c2986f8d7689d1366f92007be30bc27da1c5:2" + }, + "coin_action": "coin_created" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "33420b5518842c1d2d2ada6fc1b49d82b62c42d822345180a20e4e5f", + "tokens": [ + { + "value": "1", + "currency": { + "symbol": "526577617264", + "decimals": 0 + } + } + ] + }, + { + "policyId": "c6f192a236596e2bbaac5900d67e9700dec7c77d9da626c98e0ab2ac", + "tokens": [ + { + "value": "723045", + "currency": { + "symbol": "5061796d656e74546f6b656e", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 7, + "network_index": 3 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + }, + { + "index": 3 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1vzkswm5qxd50an9xmfulygxykkk23h8ykfcqk5ya6fwuwaspgd4wr" + }, + "amount": { + "value": "9356844", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "2125c27b7faad8007b8003ba6fd2c2986f8d7689d1366f92007be30bc27da1c5:3" + }, + "coin_action": "coin_created" + } + } + ], + "metadata": { + "size": 1461, + "scriptSize": 0 + } + } + }, + { + "block_identifier": { + "index": 3685492, + "hash": "df0910cde00e3ca65def9b86363b5f010a20da72ca35b7e17a5b5c0e34215132" + }, + "transaction": { + "transaction_identifier": { + "hash": "d9b68d4558e6a2c1e71ddabe94d7236f1b1183f1a24a71a169bc7808e05b4bc0" + }, + "operations": [ + { + "operation_identifier": { + "index": 0 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1wqd2qdzhh3x280q6erdksyku6k3eknrqsmrpkjnn6hsvjegk9gghn" + }, + "amount": { + "value": "-2000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "2b88ab5cc30ca879df308317fdac0e0527f2b493eca9566f8036dd8a6061d39f:0" + }, + "coin_action": "coin_spent" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "657991fcca11e70169ba87ef626d2a3a5bd35faa32a5946b8689a342", + "tokens": [ + { + "value": "-1", + "currency": { + "symbol": "4e6f646546656564", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 1 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1vqxf55myz6quhq03se85pcvu2uqhf6yz7k4g6hw7tygye6gqu5syq" + }, + "amount": { + "value": "-9000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "2b88ab5cc30ca879df308317fdac0e0527f2b493eca9566f8036dd8a6061d39f:1" + }, + "coin_action": "coin_spent" + } + }, + { + "operation_identifier": { + "index": 2 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1vqxf55myz6quhq03se85pcvu2uqhf6yz7k4g6hw7tygye6gqu5syq" + }, + "amount": { + "value": "-9000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "f326dc43e0126f72f0dfc74301f346d92f2560f88e835d1535d3da672bafc448:1" + }, + "coin_action": "coin_spent" + } + }, + { + "operation_identifier": { + "index": 3, + "network_index": 0 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1wqd2qdzhh3x280q6erdksyku6k3eknrqsmrpkjnn6hsvjegk9gghn" + }, + "amount": { + "value": "2000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "d9b68d4558e6a2c1e71ddabe94d7236f1b1183f1a24a71a169bc7808e05b4bc0:0" + }, + "coin_action": "coin_created" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "657991fcca11e70169ba87ef626d2a3a5bd35faa32a5946b8689a342", + "tokens": [ + { + "value": "1", + "currency": { + "symbol": "4e6f646546656564", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 4, + "network_index": 1 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1vqxf55myz6quhq03se85pcvu2uqhf6yz7k4g6hw7tygye6gqu5syq" + }, + "amount": { + "value": "9000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "d9b68d4558e6a2c1e71ddabe94d7236f1b1183f1a24a71a169bc7808e05b4bc0:1" + }, + "coin_action": "coin_created" + } + }, + { + "operation_identifier": { + "index": 5, + "network_index": 2 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1vqxf55myz6quhq03se85pcvu2uqhf6yz7k4g6hw7tygye6gqu5syq" + }, + "amount": { + "value": "8511865", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "d9b68d4558e6a2c1e71ddabe94d7236f1b1183f1a24a71a169bc7808e05b4bc0:2" + }, + "coin_action": "coin_created" + } + } + ], + "metadata": { + "size": 543, + "scriptSize": 0 + } + } + }, + { + "block_identifier": { + "index": 3685492, + "hash": "df0910cde00e3ca65def9b86363b5f010a20da72ca35b7e17a5b5c0e34215132" + }, + "transaction": { + "transaction_identifier": { + "hash": "bc5067ad9a67e0753ef97064bab09708eb859e1e1828cd87b8a51d7025c72e60" + }, + "operations": [ + { + "operation_identifier": { + "index": 0 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1wqd2qdzhh3x280q6erdksyku6k3eknrqsmrpkjnn6hsvjegk9gghn" + }, + "amount": { + "value": "-2000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "6f5760b369f148f6e84570909358f7f67c93fcc18dd65cc0b606fcc82cef1f6c:0" + }, + "coin_action": "coin_spent" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "657991fcca11e70169ba87ef626d2a3a5bd35faa32a5946b8689a342", + "tokens": [ + { + "value": "-1", + "currency": { + "symbol": "4e6f646546656564", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 1 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1vqcx34l4ltqs2s6kqtnptnn7hyf6nlh5m68f6tdhjcc3lqge7jplp" + }, + "amount": { + "value": "-8510450", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "6f5760b369f148f6e84570909358f7f67c93fcc18dd65cc0b606fcc82cef1f6c:2" + }, + "coin_action": "coin_spent" + } + }, + { + "operation_identifier": { + "index": 2 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1vqcx34l4ltqs2s6kqtnptnn7hyf6nlh5m68f6tdhjcc3lqge7jplp" + }, + "amount": { + "value": "-9000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "90fc2d88430aac0b92b598d1d8da8e210296e5989cf80955cef30a1353e24832:1" + }, + "coin_action": "coin_spent" + } + }, + { + "operation_identifier": { + "index": 3, + "network_index": 0 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1wqd2qdzhh3x280q6erdksyku6k3eknrqsmrpkjnn6hsvjegk9gghn" + }, + "amount": { + "value": "2000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "bc5067ad9a67e0753ef97064bab09708eb859e1e1828cd87b8a51d7025c72e60:0" + }, + "coin_action": "coin_created" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "657991fcca11e70169ba87ef626d2a3a5bd35faa32a5946b8689a342", + "tokens": [ + { + "value": "1", + "currency": { + "symbol": "4e6f646546656564", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 4, + "network_index": 1 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1vqcx34l4ltqs2s6kqtnptnn7hyf6nlh5m68f6tdhjcc3lqge7jplp" + }, + "amount": { + "value": "9000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "bc5067ad9a67e0753ef97064bab09708eb859e1e1828cd87b8a51d7025c72e60:1" + }, + "coin_action": "coin_created" + } + }, + { + "operation_identifier": { + "index": 5, + "network_index": 2 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1vqcx34l4ltqs2s6kqtnptnn7hyf6nlh5m68f6tdhjcc3lqge7jplp" + }, + "amount": { + "value": "8022315", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "bc5067ad9a67e0753ef97064bab09708eb859e1e1828cd87b8a51d7025c72e60:2" + }, + "coin_action": "coin_created" + } + } + ], + "metadata": { + "size": 543, + "scriptSize": 0 + } + } + }, + { + "block_identifier": { + "index": 3685492, + "hash": "df0910cde00e3ca65def9b86363b5f010a20da72ca35b7e17a5b5c0e34215132" + }, + "transaction": { + "transaction_identifier": { + "hash": "08393c389abdc955c494b8015472215f294c44c33c387729d3f550fde9d1f101" + }, + "operations": [ + { + "operation_identifier": { + "index": 0 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1wqd2qdzhh3x280q6erdksyku6k3eknrqsmrpkjnn6hsvjegk9gghn" + }, + "amount": { + "value": "-2000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "30660df6f14efd23623794a98bd22a2dd619f5cb0d618127f7725047c4f98638:0" + }, + "coin_action": "coin_spent" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "657991fcca11e70169ba87ef626d2a3a5bd35faa32a5946b8689a342", + "tokens": [ + { + "value": "-1", + "currency": { + "symbol": "4e6f646546656564", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 1 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1vzkt23fass4jgll0wuj605j09vps0lpujejsjl9h30l9lsqw5vhuq" + }, + "amount": { + "value": "-12613303", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "35e53aa20e99ab0b87a1549679c955d15b15c1a7275aca2f01087a72666c9629:2" + }, + "coin_action": "coin_spent" + } + }, + { + "operation_identifier": { + "index": 2 + }, + "type": "input", + "status": "success", + "account": { + "address": "addr_test1vzkt23fass4jgll0wuj605j09vps0lpujejsjl9h30l9lsqw5vhuq" + }, + "amount": { + "value": "-9000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "725e66ccb1e466923c27912ad7f774cf34c1b166c8d79c849767f904492b489e:1" + }, + "coin_action": "coin_spent" + } + }, + { + "operation_identifier": { + "index": 3, + "network_index": 0 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1wqd2qdzhh3x280q6erdksyku6k3eknrqsmrpkjnn6hsvjegk9gghn" + }, + "amount": { + "value": "2000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "08393c389abdc955c494b8015472215f294c44c33c387729d3f550fde9d1f101:0" + }, + "coin_action": "coin_created" + }, + "metadata": { + "tokenBundle": [ + { + "policyId": "657991fcca11e70169ba87ef626d2a3a5bd35faa32a5946b8689a342", + "tokens": [ + { + "value": "1", + "currency": { + "symbol": "4e6f646546656564", + "decimals": 0 + } + } + ] + } + ] + } + }, + { + "operation_identifier": { + "index": 4, + "network_index": 1 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1vzkt23fass4jgll0wuj605j09vps0lpujejsjl9h30l9lsqw5vhuq" + }, + "amount": { + "value": "9000000", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "08393c389abdc955c494b8015472215f294c44c33c387729d3f550fde9d1f101:1" + }, + "coin_action": "coin_created" + } + }, + { + "operation_identifier": { + "index": 5, + "network_index": 2 + }, + "related_operations": [ + { + "index": 0 + }, + { + "index": 1 + }, + { + "index": 2 + } + ], + "type": "output", + "status": "success", + "account": { + "address": "addr_test1vzkt23fass4jgll0wuj605j09vps0lpujejsjl9h30l9lsqw5vhuq" + }, + "amount": { + "value": "12125168", + "currency": { + "symbol": "ADA", + "decimals": 6 + } + }, + "coin_change": { + "coin_identifier": { + "identifier": "08393c389abdc955c494b8015472215f294c44c33c387729d3f550fde9d1f101:2" + }, + "coin_action": "coin_created" + } + } + ], + "metadata": { + "size": 543, + "scriptSize": 0 + } + } + } + ], + "total_count": 4447556, + "next_offset": 5 + } +} \ No newline at end of file diff --git a/tests/integration/test_construction_api.py b/tests/integration/test_golden_examples.py similarity index 96% rename from tests/integration/test_construction_api.py rename to tests/integration/test_golden_examples.py index f45d07358c..cd5b3026d6 100644 --- a/tests/integration/test_construction_api.py +++ b/tests/integration/test_golden_examples.py @@ -57,7 +57,7 @@ # Defaults DEFAULT_ROSETTA_URL = "http://localhost:8082" DEFAULT_BASE_DIR = ( - Path(__file__).parent / "golden_examples/rosetta_java/construction" + Path(__file__).parent / "golden_examples/rosetta_java" ).resolve() DEFAULT_OPENAPI_PATH = ( Path(__file__).parent.parent.parent @@ -91,11 +91,22 @@ GRAY = "\033[90m" # Fields that should be ignored when diffing +# Construction endpoints VOLATILE_FIELDS = { "metadata": ["metadata.ttl"], "preprocess": ["options.transaction_size"], } +# Data endpoints - add volatile fields if needed +# (e.g., timestamps that change between runs) +DATA_ENDPOINT_VOLATILE_FIELDS = { + "search": [], + "block": [], + "account": [], + "network": [], + "mempool": [], +} + # Stats stats: Dict[str, Any] = { "total_files": 0, @@ -328,7 +339,7 @@ def call_api( url, data=data, headers={"Content-Type": "application/json"} ) start = time.monotonic() - with urllib.request.urlopen(req, timeout=10) as resp: + with urllib.request.urlopen(req, timeout=90) as resp: raw = resp.read() return ( json.loads(raw.decode("utf-8")), @@ -406,8 +417,26 @@ def deep_diff( # --------------------- File + Result logic --------------------- def determine_endpoint(file_path: Path) -> str: + """Determine API endpoint from test file. + + Priority: + 1. Explicit 'endpoint' field in test file (preferred for data endpoints) + 2. Path-based detection for construction/ directory structure + """ + # Try to read endpoint from test file first + try: + test = json.loads(file_path.read_text(encoding="utf-8")) + if "endpoint" in test: + return test["endpoint"] + except Exception: + pass + + # Fallback: derive from path (construction endpoints) try: rel = file_path.resolve().relative_to(Path(BASE_PATH).resolve()) + # Handle both old structure (construction/X) and new (construction/X or data/X) + if rel.parts[0] == "construction" and len(rel.parts) > 1: + return f"/construction/{rel.parts[1]}" return f"/construction/{rel.parts[0]}" except Exception: parts = list(file_path.resolve().parts) @@ -418,7 +447,8 @@ def determine_endpoint(file_path: Path) -> str: def get_ignore_paths(endpoint: str) -> List[str]: - return VOLATILE_FIELDS.get(endpoint.split("/")[-1], []) + endpoint_key = endpoint.split("/")[-1] + return VOLATILE_FIELDS.get(endpoint_key, DATA_ENDPOINT_VOLATILE_FIELDS.get(endpoint_key, [])) def _fmt_bytes(n: Any) -> str: @@ -535,6 +565,9 @@ def validate_file(file_path: Path) -> Dict[str, Any]: } try: test = json.loads(Path(file_path).read_text(encoding="utf-8")) + if "skip_reason" in test: + res.update({"status": "skipped", "error": test["skip_reason"]}) + return res if "request_body" not in test: res.update({"status": "skipped", "error": "No request_body found"}) return res @@ -878,7 +911,7 @@ def main() -> None: flist = files_by_endpoint[endpoint] name = endpoint.split("/")[-1] print("") - print(f"{BOLD}Testing /construction/{name} ({len(flist)} files){RESET}") + print(f"{BOLD}Testing {endpoint} ({len(flist)} files){RESET}") print("-" * 40) ep_passed = ep_failed = ep_skipped = ep_errors = 0 @@ -916,12 +949,8 @@ def main() -> None: ) schemas_panel = None if SCHEMA_VALIDATOR and SCHEMA_VALIDATOR.enabled: - suc = SCHEMA_VALIDATOR.get_resolved_schema( - f"/construction/{name}", 200 - ) - err = SCHEMA_VALIDATOR.get_resolved_schema( - f"/construction/{name}", 500 - ) + suc = SCHEMA_VALIDATOR.get_resolved_schema(endpoint, 200) + err = SCHEMA_VALIDATOR.get_resolved_schema(endpoint, 500) ssum = SCHEMA_VALIDATOR.summarize_schema(suc) if suc else None esum = SCHEMA_VALIDATOR.summarize_schema(err) if err else None if ssum or esum: @@ -1177,7 +1206,7 @@ def main() -> None: RICH_CONSOLE.print( Panel( content, - title=f"\nSummary /construction/{name}", + title=f"\nSummary {endpoint}", border_style="white", expand=True, ) @@ -1214,7 +1243,7 @@ def main() -> None: stats["endpoint_summaries"].append( { - "endpoint": f"/construction/{name}", + "endpoint": endpoint, "passed": ep_passed, "failed": ep_failed, "skipped": ep_skipped, diff --git a/tests/load-tests/.env.example b/tests/load-tests/.env.example new file mode 100644 index 0000000000..6f5c870d92 --- /dev/null +++ b/tests/load-tests/.env.example @@ -0,0 +1,13 @@ +# Database connection for populating test data from Yaci Store +# Copy this file to .env and fill in your values + +# Database connection (default rosetta-java credentials) +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=rosetta-java +DB_USER=rosetta_db_admin +DB_PASSWORD=weakpwd#123_d +DB_SCHEMA=public + +# Alternative: use a connection string +# DATABASE_URL=postgresql://rosetta_db_admin:weakpwd#123_d@localhost:5432/rosetta-java diff --git a/tests/load-tests/.gitignore b/tests/load-tests/.gitignore new file mode 100644 index 0000000000..eef5deb249 --- /dev/null +++ b/tests/load-tests/.gitignore @@ -0,0 +1,20 @@ +# Environment files with credentials +.env + +# Python cache +__pycache__/ +*.py[cod] +*$py.class + +# Virtual environment +.venv/ + +# Locust reports +*.html +*_stats.csv +*_stats_history.csv +*_failures.csv +*_exceptions.csv + +# Test data backups +test_data.py.bak diff --git a/tests/load-tests/.python-version b/tests/load-tests/.python-version new file mode 100644 index 0000000000..e4fba21835 --- /dev/null +++ b/tests/load-tests/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/tests/load-tests/README.md b/tests/load-tests/README.md new file mode 100644 index 0000000000..dc9c573a95 --- /dev/null +++ b/tests/load-tests/README.md @@ -0,0 +1,240 @@ +# Locust Load Testing for Cardano Rosetta API + +This directory contains a **prototype** Locust-based load testing setup for comparing against the existing Apache Bench (`ab`) stability tests. + +## 🎯 Purpose (Spike Investigation) + +This is a **spike** to evaluate whether Locust can provide better insights than Apache Bench by: + +1. **Varying data per request** - avoiding database caching bias +2. **Categorizing data** - revealing performance patterns (light/medium/heavy loads) +3. **Tracking metrics by category** - identifying which data types are slow +4. **Providing richer metrics** - p95/p99, real-time UI, per-endpoint breakdown + +## 🏗️ Architecture + +``` +tests/load-tests/ +├── pyproject.toml # uv dependencies (locust, python-dotenv) +├── locustfile.py # Main load test with all 7 endpoints +├── test_data.py # Categorized test data (light/medium/heavy) +└── README.md # This file +``` + +## 📦 Setup + +```bash +cd tests/load-tests + +# Install dependencies with uv +uv sync + +# Activate virtual environment +source .venv/bin/activate +``` + +## 🗄️ Populate Test Data + +Before running load tests, you need to populate `test_data.py` with real preprod data. + +### Step 1: Port-forward the Yaci Store Database + +```bash +# SSH into preview machine and forward PostgreSQL port +ssh -L 5432:localhost:5432 preview +``` + +### Step 2: Configure Database Connection + +```bash +# Copy example environment file +cp .env.example .env + +# Edit .env with your database credentials +# DB_HOST=localhost +# DB_PORT=5432 +# DB_NAME=preprod +# DB_USER=postgres +# DB_PASSWORD=your_password +``` + +### Step 3: Run the Population Script + +```bash +uv run python populate_test_data.py +``` + +This will: +- Query Yaci Store database for diverse addresses/blocks/transactions +- Categorize by performance characteristics (light/medium/heavy) +- Generate `test_data.py` with real preprod data + +**Expected output:** +``` +📍 Querying addresses... + ✓ Light addresses (1-10 UTXOs): 10 + ✓ Medium addresses (100-1K UTXOs): 10 + ✓ Heavy addresses (10K+ UTXOs): 10 + +🧱 Querying blocks... + ✓ Light blocks (1-5 txs): 5 + ✓ Heavy blocks (100+ txs): 5 + +📄 Querying transactions... + ✓ Small transactions (<500 bytes): 10 + ✓ Large transactions (>10KB): 10 +``` + +## 🚀 Usage + +### 1. Port-forward Preprod Rosetta Instance + +```bash +# SSH into preview server and forward port 8082 +ssh -L 8082:localhost:8082 preview +``` + +### 2. Run Locust + +**Web UI Mode (Recommended for exploration):** +```bash +uv run locust --host=http://localhost:8082 +``` + +Then open http://localhost:8089 in your browser to: +- Set number of users +- Set spawn rate +- Monitor real-time metrics +- View charts and breakdowns + +**Headless Mode (CI/CD friendly):** +```bash +uv run locust --host=http://localhost:8082 \ + --users 50 \ + --spawn-rate 5 \ + --run-time 300s \ + --headless +``` + +**Generate HTML Report:** +```bash +uv run locust --host=http://localhost:8082 \ + --users 50 \ + --spawn-rate 5 \ + --run-time 300s \ + --headless \ + --html=report.html \ + --csv=results +``` + +This creates: +- `report.html` - Interactive HTML report +- `results_stats.csv` - Request statistics +- `results_stats_history.csv` - Time-series data +- `results_failures.csv` - Failure details + +## 📊 Metrics Provided + +Locust provides these metrics **out of the box**: + +- **Response time percentiles**: p50, p66, p75, p80, p90, p95, p99 +- **Throughput**: Requests per second (RPS) +- **Failure rate**: Count and percentage +- **Per-endpoint breakdown**: All metrics split by endpoint +- **Per-category breakdown**: Metrics split by data category (light/medium/heavy) + +### Example Output: + +``` +/account/balance [light] + Requests: 7000 + Failures: 0 + Avg: 45.23ms + p95: 89.12ms + p99: 123.45ms + +/account/balance [heavy] + Requests: 1000 + Failures: 0 + Avg: 456.78ms + p95: 890.12ms + p99: 1234.56ms +``` + +This clearly shows that **heavy addresses (10K+ UTXOs) are ~10x slower** - something that Apache Bench's identical payloads would miss! + +## 🎭 Comparison with Apache Bench + +| Feature | Apache Bench | Locust | +|---------|-------------|---------| +| **Data variation** | ❌ Identical payload | ✅ Categorized data | +| **Cache bias** | ❌ Heavy caching | ✅ Avoids caching | +| **Percentiles** | ✅ p95, p99 | ✅ p50-p99 | +| **Real-time UI** | ❌ CLI only | ✅ Web UI | +| **Endpoint weights** | ❌ Manual | ✅ Task decorators | +| **Category tracking** | ❌ Not possible | ✅ Built-in | +| **CI/CD** | ✅ Scriptable | ✅ Headless mode | +| **Reports** | 📊 Text output | 📊 HTML + CSV | + +## 📝 Test Data Structure + +Data is organized in `test_data.py` by **categories**: + +```python +ADDRESSES = { + "light": [...], # 1-10 UTXOs (fast) + "medium": [...], # 100-1K UTXOs (moderate) + "heavy": [...] # 10K+ UTXOs (slow) +} + +BLOCKS = { + "light": [...], # 1-5 transactions + "heavy": [...] # 100+ transactions +} + +TRANSACTIONS = { + "small": [...], # <500 bytes + "large": [...] # >10KB +} +``` + +**Weights** control distribution: +```python +CATEGORY_WEIGHTS = { + "address_light": 0.7, # 70% of requests + "address_heavy": 0.1, # 10% of requests +} +``` + +## 🔧 Next Steps (TODOs) + +- [ ] **Populate test_data.py** with actual preprod addresses/blocks/transactions + - Query preprod Rosetta to find addresses with varying UTXO counts + - Identify light vs heavy blocks + - Categorize transactions by size +- [ ] **Run comparison test**: ab vs Locust with identical vs varied data +- [ ] **Document findings**: metrics differences, insights, recommendations +- [ ] **Decide**: Full migration? Hybrid approach? Keep current ab tests? + +## 🎯 Success Criteria + +This spike is successful if: + +1. ✅ Locust can vary data per request +2. ✅ Metrics reveal performance degradation patterns by category +3. ✅ p95/p99 metrics match or exceed ab capabilities +4. ✅ CI/CD integration path is clear +5. ⏳ Comparison shows meaningful differences vs ab + +## 🚫 Out of Scope (for this spike) + +- Full implementation (prototype only) +- Grafana/monitoring integration +- Automated CSV generation +- Full endpoint coverage (7 endpoints is enough for spike) + +## 📚 Resources + +- [Locust Documentation](https://docs.locust.io/) +- [Task #638: Replace ab with Locust](https://github.com/cardano-foundation/cardano-rosetta-java/issues/638) +- Existing ab tests: `../../load-tests/stability_test.py` diff --git a/tests/load-tests/locustfile.py b/tests/load-tests/locustfile.py new file mode 100644 index 0000000000..454c7330f5 --- /dev/null +++ b/tests/load-tests/locustfile.py @@ -0,0 +1,340 @@ +""" +Locust load testing for Cardano Rosetta API with categorized data. + +This demonstrates the key advantage over Apache Bench: ability to cycle through +CATEGORIZED test data per request, revealing performance patterns and avoiding +database caching bias. + +The data is organized by categories (light/medium/heavy) to measure how +performance degrades with data complexity (UTXO count, block size, tx size). + +Usage: + # Port-forward preprod Rosetta instance first: + ssh -L 8082:localhost:8082 preview + + # Web UI mode (real-time monitoring) + uv run locust --host=http://localhost:8082 + + # Headless mode (CI/CD friendly) + uv run locust --host=http://localhost:8082 \ + --users 10 --spawn-rate 2 --run-time 60s --headless + + # Generate HTML report + uv run locust --host=http://localhost:8082 \ + --users 50 --spawn-rate 5 --run-time 300s --headless \ + --html=report.html +""" + +import random +from typing import Dict, List, Tuple + +from locust import HttpUser, between, events, task + +from test_data import ( + ADDRESSES, + BLOCKS, + CATEGORY_WEIGHTS, + CONSTRUCTION_METADATA, + NETWORK, + TRANSACTIONS, +) + + +class CategorizedDataProvider: + """ + Provides test data based on categories and weights. + + This allows us to: + 1. Control distribution (70% light, 20% medium, 10% heavy) + 2. Track performance by category + 3. Reveal degradation patterns + """ + + @staticmethod + def get_weighted_choice( + items_dict: Dict[str, List], weight_prefix: str + ) -> Tuple[str, any]: + """ + Select an item from a categorized dictionary based on weights. + + Returns: (category, item) + """ + categories = list(items_dict.keys()) + weights = [ + CATEGORY_WEIGHTS.get(f"{weight_prefix}_{cat}", 1.0) for cat in categories + ] + + # Normalize weights to sum to 1.0 + total = sum(weights) + normalized_weights = [w / total for w in weights] + + # Choose category based on weights + category = random.choices(categories, weights=normalized_weights)[0] + + # Choose random item from that category + items = items_dict[category] + if not items: + # Fallback to first available category if selected category is empty + for cat, cat_items in items_dict.items(): + if cat_items: + return cat, random.choice(cat_items) + raise ValueError(f"No data available in {weight_prefix}") + + item = random.choice(items) + return category, item + + +data_provider = CategorizedDataProvider() + + +class RosettaUser(HttpUser): + """ + Simulates a user making requests to Cardano Rosetta API. + + Task weights simulate realistic traffic distribution: + - Account Balance: 10x (most common) + - Account Coins: 8x + - Search Transactions: 5x + - Block: 5x + - Block Transaction: 3x + - Construction Metadata: 2x + - Network Status: 1x (baseline) + """ + + # Wait 1-3 seconds between requests (simulates real user behavior) + wait_time = between(1, 3) + + @task(1) + def network_status(self): + """ + Test /network/status endpoint. + + Weight: 1 (baseline) + No data variation needed. + """ + payload = { + "network_identifier": {"blockchain": "cardano", "network": NETWORK}, + "metadata": {}, + } + + with self.client.post( + "/network/status", json=payload, catch_response=True, name="/network/status" + ) as response: + if response.status_code == 200: + response.success() + else: + response.failure(f"Status {response.status_code}") + + @task(10) + def account_balance(self): + """ + Test /account/balance with CATEGORIZED addresses. + + Weight: 10 (most frequent) + Reveals performance degradation with UTXO count: + - Light addresses: fast + - Medium addresses: moderate + - Heavy addresses: slow (10K+ UTXOs) + """ + category, address = data_provider.get_weighted_choice(ADDRESSES, "address") + + payload = { + "network_identifier": {"blockchain": "cardano", "network": NETWORK}, + "account_identifier": {"address": address}, + } + + with self.client.post( + "/account/balance", + json=payload, + catch_response=True, + name=f"/account/balance [{category}]", # Track by category + ) as response: + if response.status_code == 200: + response.success() + else: + response.failure(f"Status {response.status_code}") + + @task(8) + def account_coins(self): + """ + Test /account/coins with CATEGORIZED addresses. + + Weight: 8 + Similar to account/balance but includes mempool. + """ + category, address = data_provider.get_weighted_choice(ADDRESSES, "address") + + payload = { + "network_identifier": {"blockchain": "cardano", "network": NETWORK}, + "account_identifier": {"address": address}, + } + + with self.client.post( + "/account/coins", + json=payload, + catch_response=True, + name=f"/account/coins [{category}]", + ) as response: + if response.status_code == 200: + response.success() + else: + response.failure(f"Status {response.status_code}") + + @task(5) + def block(self): + """ + Test /block with CATEGORIZED blocks. + + Weight: 5 + Reveals performance degradation with block size: + - Light blocks (1-5 txs): fast + - Heavy blocks (100+ txs): slow + """ + category, block = data_provider.get_weighted_choice(BLOCKS, "block") + + payload = { + "network_identifier": {"blockchain": "cardano", "network": NETWORK}, + "block_identifier": {"index": block["index"], "hash": block["hash"]}, + } + + with self.client.post( + "/block", json=payload, catch_response=True, name=f"/block [{category}]" + ) as response: + if response.status_code == 200: + response.success() + else: + response.failure(f"Status {response.status_code}") + + @task(3) + def block_transaction(self): + """ + Test /block/transaction with CATEGORIZED transactions. + + Weight: 3 + Reveals performance with transaction complexity. + """ + category, tx = data_provider.get_weighted_choice(TRANSACTIONS, "tx") + + payload = { + "network_identifier": {"blockchain": "cardano", "network": NETWORK}, + "block_identifier": {"index": tx["block_index"], "hash": tx["block_hash"]}, + "transaction_identifier": {"hash": tx["hash"]}, + } + + with self.client.post( + "/block/transaction", + json=payload, + catch_response=True, + name=f"/block/transaction [{category}]", + ) as response: + if response.status_code == 200: + response.success() + else: + response.failure(f"Status {response.status_code}") + + @task(5) + def search_transactions(self): + """ + Test /search/transactions with CATEGORIZED transactions. + + Weight: 5 + """ + category, tx = data_provider.get_weighted_choice(TRANSACTIONS, "tx") + + payload = { + "network_identifier": {"blockchain": "cardano", "network": NETWORK}, + "transaction_identifier": {"hash": tx["hash"]}, + } + + with self.client.post( + "/search/transactions", + json=payload, + catch_response=True, + name=f"/search/transactions [{category}]", + ) as response: + if response.status_code == 200: + response.success() + else: + response.failure(f"Status {response.status_code}") + + @task(2) + def construction_metadata(self): + """ + Test /construction/metadata with CATEGORIZED sizes. + + Weight: 2 + Reveals performance with transaction size estimation. + """ + category, metadata = data_provider.get_weighted_choice( + CONSTRUCTION_METADATA, "construction" + ) + + payload = { + "network_identifier": {"blockchain": "cardano", "network": NETWORK}, + "options": { + "transaction_size": metadata["transaction_size"], + "relative_ttl": metadata["relative_ttl"], + }, + } + + with self.client.post( + "/construction/metadata", + json=payload, + catch_response=True, + name=f"/construction/metadata [{category}]", + ) as response: + if response.status_code == 200: + response.success() + else: + response.failure(f"Status {response.status_code}") + + +@events.test_start.add_listener +def on_test_start(environment, **kwargs): + """Event handler called when test starts.""" + print("=" * 80) + print(f"Starting Locust load test") + print(f"Target: {environment.host}") + print(f"Network: {NETWORK}") + print(f"Data categories loaded:") + print(f" - Addresses: {sum(len(v) for v in ADDRESSES.values())} total") + for cat, items in ADDRESSES.items(): + print( + f" - {cat}: {len(items)} items (weight: {CATEGORY_WEIGHTS.get(f'address_{cat}', 1.0)})" + ) + print(f" - Blocks: {sum(len(v) for v in BLOCKS.values())} total") + for cat, items in BLOCKS.items(): + print( + f" - {cat}: {len(items)} items (weight: {CATEGORY_WEIGHTS.get(f'block_{cat}', 1.0)})" + ) + print(f" - Transactions: {sum(len(v) for v in TRANSACTIONS.values())} total") + for cat, items in TRANSACTIONS.items(): + print( + f" - {cat}: {len(items)} items (weight: {CATEGORY_WEIGHTS.get(f'tx_{cat}', 1.0)})" + ) + print("=" * 80) + + +@events.test_stop.add_listener +def on_test_stop(environment, **kwargs): + """Event handler called when test stops.""" + print("=" * 80) + print(f"Load test completed") + print(f"Total requests: {environment.stats.total.num_requests}") + print(f"Total failures: {environment.stats.total.num_failures}") + print(f"Average response time: {environment.stats.total.avg_response_time:.2f}ms") + print(f"p95: {environment.stats.total.get_response_time_percentile(0.95):.2f}ms") + print(f"p99: {environment.stats.total.get_response_time_percentile(0.99):.2f}ms") + print(f"Requests/sec: {environment.stats.total.total_rps:.2f}") + print("=" * 80) + print("\nPer-endpoint breakdown:") + print("-" * 80) + for name, stats in environment.stats.entries.items(): + if stats.num_requests > 0: + print(f"{name}") + print(f" Requests: {stats.num_requests}") + print(f" Failures: {stats.num_failures}") + print(f" Avg: {stats.avg_response_time:.2f}ms") + print(f" p95: {stats.get_response_time_percentile(0.95):.2f}ms") + print(f" p99: {stats.get_response_time_percentile(0.99):.2f}ms") + print("=" * 80) diff --git a/tests/load-tests/main.py b/tests/load-tests/main.py new file mode 100644 index 0000000000..e433c40266 --- /dev/null +++ b/tests/load-tests/main.py @@ -0,0 +1,6 @@ +def main(): + print("Hello from load-tests!") + + +if __name__ == "__main__": + main() diff --git a/tests/load-tests/populate_test_data.py b/tests/load-tests/populate_test_data.py new file mode 100755 index 0000000000..b31e5c092e --- /dev/null +++ b/tests/load-tests/populate_test_data.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python3 +""" +Helper script to populate test_data.py with real preprod data from Yaci Store DB. + +Usage: + 1. Port-forward: ssh -L 5435:localhost:5435 preview + 2. Run: uv run python populate_test_data.py +""" + +import os +import sys +from typing import List, Dict +from dotenv import load_dotenv + +try: + import psycopg2 + from psycopg2.extras import RealDictCursor +except ImportError: + print("Error: psycopg2 not installed. Run: uv add psycopg2-binary") + sys.exit(1) + +load_dotenv() + +DB_CONFIG = { + 'host': os.getenv('DB_HOST', 'localhost'), + 'port': os.getenv('DB_PORT', '5435'), + 'database': os.getenv('DB_NAME', 'rosetta-java'), + 'user': os.getenv('DB_USER', 'rosetta_db_admin'), + 'password': os.getenv('DB_PASSWORD', ''), +} + +DATABASE_URL = os.getenv('DATABASE_URL') +TARGET_PER_CATEGORY = 10 + + +class YaciDBQuerier: + """Query Yaci Store database for categorized test data.""" + + def __init__(self): + self.conn = None + self.schema = os.getenv('DB_SCHEMA', 'public') + + def connect(self): + """Establish database connection.""" + try: + if DATABASE_URL: + self.conn = psycopg2.connect(DATABASE_URL) + else: + self.conn = psycopg2.connect(**DB_CONFIG) + self.conn.autocommit = True # Prevent transaction issues + print(f"✓ Connected to database: {DB_CONFIG['database']}") + print(f"✓ Using schema: {self.schema}") + except Exception as e: + print(f"✗ Database connection failed: {e}") + sys.exit(1) + + def close(self): + if self.conn: + self.conn.close() + + def get_light_addresses(self) -> List[str]: + """Find addresses with 1-10 UTXOs (fast queries).""" + query = f""" + SELECT owner_addr, COUNT(*) as utxo_count + FROM {self.schema}.address_utxo + WHERE owner_addr IS NOT NULL + GROUP BY owner_addr + HAVING COUNT(*) BETWEEN 1 AND 10 + ORDER BY RANDOM() + LIMIT %s + """ + return self._execute_query(query, (TARGET_PER_CATEGORY,), fetch_column='owner_addr') + + def get_medium_addresses(self) -> List[str]: + """Find addresses with 100-1000 UTXOs (moderate load).""" + query = f""" + SELECT owner_addr, COUNT(*) as utxo_count + FROM {self.schema}.address_utxo + WHERE owner_addr IS NOT NULL + GROUP BY owner_addr + HAVING COUNT(*) BETWEEN 100 AND 1000 + ORDER BY RANDOM() + LIMIT %s + """ + return self._execute_query(query, (TARGET_PER_CATEGORY,), fetch_column='owner_addr') + + def get_heavy_addresses(self) -> List[str]: + """Find addresses with 10000+ UTXOs (slow queries).""" + query = f""" + SELECT owner_addr, COUNT(*) as utxo_count + FROM {self.schema}.address_utxo + WHERE owner_addr IS NOT NULL + GROUP BY owner_addr + HAVING COUNT(*) >= 10000 + ORDER BY RANDOM() + LIMIT %s + """ + return self._execute_query(query, (TARGET_PER_CATEGORY,), fetch_column='owner_addr') + + def get_light_blocks(self) -> List[Dict]: + """Find blocks with 1-5 transactions (fast to process).""" + query = f""" + SELECT number as index, hash, no_of_txs as tx_count + FROM {self.schema}.block + WHERE no_of_txs BETWEEN 1 AND 5 + ORDER BY RANDOM() + LIMIT %s + """ + return self._execute_query(query, (TARGET_PER_CATEGORY // 2,)) + + def get_heavy_blocks(self) -> List[Dict]: + """Find blocks with 100+ transactions (slow to process).""" + query = f""" + SELECT number as index, hash, no_of_txs as tx_count + FROM {self.schema}.block + WHERE no_of_txs >= 100 + ORDER BY RANDOM() + LIMIT %s + """ + return self._execute_query(query, (TARGET_PER_CATEGORY // 2,)) + + def get_small_transactions(self) -> List[Dict]: + """Find transactions with few inputs/outputs (simple).""" + query = f""" + SELECT + t.tx_hash as hash, + t.block as block_index, + t.block_hash, + jsonb_array_length(t.inputs) as input_count, + jsonb_array_length(t.outputs) as output_count + FROM {self.schema}.transaction t + WHERE + jsonb_array_length(t.inputs) <= 2 + AND jsonb_array_length(t.outputs) <= 2 + AND t.block IS NOT NULL + ORDER BY RANDOM() + LIMIT %s + """ + return self._execute_query(query, (TARGET_PER_CATEGORY,)) + + def get_large_transactions(self) -> List[Dict]: + """Find transactions with many inputs/outputs (complex).""" + query = f""" + SELECT + t.tx_hash as hash, + t.block as block_index, + t.block_hash, + jsonb_array_length(t.inputs) as input_count, + jsonb_array_length(t.outputs) as output_count + FROM {self.schema}.transaction t + WHERE + (jsonb_array_length(t.inputs) >= 10 + OR jsonb_array_length(t.outputs) >= 10) + AND t.block IS NOT NULL + ORDER BY RANDOM() + LIMIT %s + """ + return self._execute_query(query, (TARGET_PER_CATEGORY,)) + + def _execute_query(self, query: str, params: tuple = (), fetch_column: str = None) -> List: + """Execute query and return results.""" + try: + with self.conn.cursor(cursor_factory=RealDictCursor) as cur: + cur.execute(query, params) + results = cur.fetchall() + + if fetch_column: + return [row[fetch_column] for row in results if row[fetch_column]] + else: + return [dict(row) for row in results] + + except Exception as e: + print(f"✗ Query failed: {e}") + return [] + + +def generate_test_data_file(querier: YaciDBQuerier): + """Generate test_data.py with real preprod data.""" + + print("\n" + "=" * 80) + print("Querying Yaci Store database for categorized test data...") + print("=" * 80) + + print("\n📍 Querying addresses...") + light_addrs = querier.get_light_addresses() + print(f" ✓ Light addresses (1-10 UTXOs): {len(light_addrs)}") + + medium_addrs = querier.get_medium_addresses() + print(f" ✓ Medium addresses (100-1K UTXOs): {len(medium_addrs)}") + + heavy_addrs = querier.get_heavy_addresses() + print(f" ✓ Heavy addresses (10K+ UTXOs): {len(heavy_addrs)}") + + print("\n🧱 Querying blocks...") + light_blocks = querier.get_light_blocks() + print(f" ✓ Light blocks (1-5 txs): {len(light_blocks)}") + + heavy_blocks = querier.get_heavy_blocks() + print(f" ✓ Heavy blocks (100+ txs): {len(heavy_blocks)}") + + print("\n📄 Querying transactions...") + small_txs = querier.get_small_transactions() + print(f" ✓ Small transactions (few inputs/outputs): {len(small_txs)}") + + large_txs = querier.get_large_transactions() + print(f" ✓ Large transactions (many inputs/outputs): {len(large_txs)}") + + print("\n📝 Generating test_data.py...") + + content = f'''""" +Test data for Locust load testing - Preprod Network. + +AUTO-GENERATED by populate_test_data.py from Yaci Store database. +DO NOT EDIT MANUALLY - regenerate by running: uv run python populate_test_data.py +""" + +# Network configuration +NETWORK = "preprod" + +# Addresses categorized by UTXO count +ADDRESSES = {{ + "light": {light_addrs}, + "medium": {medium_addrs}, + "heavy": {heavy_addrs}, +}} + +# Blocks categorized by transaction count +BLOCKS = {{ + "light": {light_blocks}, + "heavy": {heavy_blocks}, +}} + +# Transactions categorized by complexity (inputs/outputs count) +TRANSACTIONS = {{ + "small": {small_txs}, + "large": {large_txs}, +}} + +# Construction metadata test cases +CONSTRUCTION_METADATA = {{ + "small_tx": [ + {{"transaction_size": 500, "relative_ttl": 1000}}, + {{"transaction_size": 800, "relative_ttl": 1500}}, + ], + "large_tx": [ + {{"transaction_size": 15000, "relative_ttl": 3600}}, + {{"transaction_size": 20000, "relative_ttl": 7200}}, + ], +}} + +# Weights control the distribution of requests across categories +CATEGORY_WEIGHTS = {{ + "address_light": 0.7, + "address_medium": 0.2, + "address_heavy": 0.1, + + "block_light": 0.8, + "block_heavy": 0.2, + + "tx_small": 0.7, + "tx_large": 0.3, + + "construction_small": 0.6, + "construction_large": 0.4, +}} +''' + + with open('test_data.py', 'w') as f: + f.write(content) + + print(" ✓ test_data.py generated successfully!") + + print("\n" + "=" * 80) + print("Summary:") + print("=" * 80) + print(f"Total addresses: {len(light_addrs) + len(medium_addrs) + len(heavy_addrs)}") + print(f"Total blocks: {len(light_blocks) + len(heavy_blocks)}") + print(f"Total transactions: {len(small_txs) + len(large_txs)}") + print("\n✓ Ready for load testing!") + print("\nNext steps:") + print(" 1. Review test_data.py to verify data quality") + print(" 2. Port-forward Rosetta API: ssh -L 8082:localhost:8082 preview") + print(" 3. Run Locust: uv run locust --host=http://localhost:8082") + + +def main(): + print("Preprod Load Test Data Generator") + print("=" * 80) + + querier = YaciDBQuerier() + + try: + querier.connect() + generate_test_data_file(querier) + finally: + querier.close() + + +if __name__ == "__main__": + main() diff --git a/tests/load-tests/pyproject.toml b/tests/load-tests/pyproject.toml new file mode 100644 index 0000000000..3c1468bd6f --- /dev/null +++ b/tests/load-tests/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "load-tests" +version = "0.1.0" +description = "Add your description here" +requires-python = ">=3.12" +dependencies = [ + "locust>=2.42.3", + "psycopg2-binary>=2.9.11", + "python-dotenv>=1.2.1", +] diff --git a/tests/load-tests/test_data.py b/tests/load-tests/test_data.py new file mode 100644 index 0000000000..cb1a8d80c0 --- /dev/null +++ b/tests/load-tests/test_data.py @@ -0,0 +1,56 @@ +""" +Test data for Locust load testing - Preprod Network. + +AUTO-GENERATED by populate_test_data.py from Yaci Store database. +DO NOT EDIT MANUALLY - regenerate by running: uv run python populate_test_data.py +""" + +# Network configuration +NETWORK = "preprod" + +# Addresses categorized by UTXO count +ADDRESSES = { + "light": ['addr_test1vpu98njlmzp5406al9cnujld0gq8mzurh2655y4l7qr9tms7wdc66', 'addr_test1qraudqut00yxlm2rd4d53ygjjztg2mk2gy5kjh6qy8ljpm3g3292mxuf3kq7nysjumlxjrlsfn9tp85r0l54l29x3qcs75n4j6', 'addr_test1vqd6nscqhpx9dk3zwrwukzwef3l050z0nys3vutq6yz5c7glclh77', 'addr_test1vztfh3gc8ega520qal5lv6dz0ydt6fhcz65x59dj4lhv0agc5dt4h', 'KjgoiXJS2con6pZQFx9UR1SzXYTDb4KLfmsQmrH3ZnN7R7oQDCtoG3mxXTeFPofy1uekwUP8RQ2kWSV4eB4SJ4ZD2iFnXECwPvy7PoXXZhjC', 'addr_test1vpef4cx46pz27xal8tey2w5h3exyapfe3u7vwt8rkvgdlsqtfm27v', 'addr_test1vq5edvurt4cxl8zyckzx0gsu7ycr7hls6feke9a7rtl7x7g74c8nq', 'addr_test1qzcdtu8ezk7270wwwy5cx96nk33q02pmuh06h2eh95puv4x6ududyye89rmj83hv788fpfcw79df656r86jnnu587jdsdnwysq', 'addr_test1qqyaww9l9wmwd05hr7pfdv5kwskp5anwhzamaxarcfhggf7a7yd2n0a98q8tzvaz2qujsl2jem8jt9ddp63veshz5hks6fgr00', 'addr_test1vrz92ng79nc4rf0673ev422alxg74l450cpljy4prgh6lccnu2skj'], + "medium": ['addr_test1zprvze2el2ecdrx0t0euqxxyk5zuy4jjewq5gqzlc2j9cd4s92sh3xwt0zcre2932qntdpd85r4ppa7cqe6gvmtwxgfsmahfs4', 'addr_test1qqvpfagzal48n7dg3279hyke7neh458u9pqm9x0s6q4vqud0y24upx4r8nxa9wveg6kys8h4rctzhgf9c4yjueqtqmeqsj4ke3', 'addr_test1qzp2a7ux93jph3n64eewufrqa82y0j3ag2r4vggxu2z9kcdlpk0qnjke5t9mr57j89t4dxhzsujprvyhr6w7n4nytt9s2a9s6q', 'addr_test1qrjde7acgmjpux7237808pclpdl4h9quts3ja7g4jm7w68wmeu7x6nvnlr6zgmy5rpy9fxyn3fpkxh9sv52pqgu0wywq5tfjw0', 'addr_test1wq20c349uqjnzemmvyvgwukgznjp4h9ezmk9czpxsdwz67q4g7xm7', 'addr_test1qr04qurckrj9vcugeu3jdneh3m6gg228fdgek2t3dzz7z6fez06qrmdhdrh7pcf96lyr74mm6g4yfcwps5nrqtnwc68q2zu0kv', 'addr_test1qpxumpuvtt7d07vqnhees96mztzj74fyt680q65cmrjtkknvum4m3utcgk9rfcevwg4zj5p8epvu68t2yhvd9wezvg0qanh287', 'addr_test1qq5thkqe6yqteekdahfqqh9q48frgzd4954kk2eknyz5eypu2qs6rsgt5w5gejhdkly2ph4uqlcwfgarchx2qwc72ufsd2spfs', 'addr_test1qpdg2wjrcvzjjn3nedrdnm248uqlm8jed2zcjzwmxyn2qe59qu90y49gamr5rj7d7ndy8mfe7emslxq5mppdjywq0f4qxkkuaq', 'addr_test1qz5nl4t5xwa5vut8smt4upk64v5dj5rkdupp6vwam2hplev7k9fcwefqwx9h3vlqjhvqt2qntxhdugzvr83c5al6tptqd5xnff'], + "heavy": ['addr_test1zr5ghvm0m8463gfjsvdwg09uerslfqkc7u5wcxueh7kf8mhxq98rskrmxdgx4hmax4uuqrklkzg0n52fk5gug57g7cts2ath6s', 'addr_test1wzdlt3c5azanf2hranc7pvt7lstd8f8lpjm38z9ld7jvx9s2746hp', 'addr_test1vz68ktz3tm33vwqkkhtg2c885unc6t9qkx2m7g04d38dquqa336hu', 'addr_test1qqq0vvmxc4gmz3e309q5hhmgfd9djaztjwcnjvfy06ezckwa54ce6qqms3qv3gf4pxy2jy88m6txz522q0vl5pznntrsxtcrv0', 'addr_test1wr7wkztlrpgjtr3y5hdy85lte0r04r9gg20m5mxer8hq34c0c496l', 'addr_test1vrkzm32hu4rks450dfc5w56lyjklk9ru72czs6heexfv5ms4aj7ym', 'addr_test1vpzn75adlmduxp26jekd9fl2le4md5plugzyxc8q27lr9jct64r5f', 'addr_test1vpmr498q23kh4hzn9qjtv9cuynpac5zh7sffklwt22hlmmqv3wufq', 'addr_test1vry2786k5pv7s365qxyvf7mhwt3h6ew6cn5a8uj84hscx2chmj38d', 'addr_test1vphrwwxg0utzm847w520zq33w9wjcjqwxf6pxc8myu6yjwcf89zt9'], +} + +# Blocks categorized by transaction count +BLOCKS = { + "light": [{'index': 2540949, 'hash': '524b36dea0af8dc774454a9c5c51b1c3619e2d41723e314f79fe2ddad8a25d45', 'tx_count': 1}, {'index': 2462234, 'hash': '8ed8f7774b6cafe544ce289e23384c75969f5d3aaba402016c39fc46c90cd4ff', 'tx_count': 1}, {'index': 1301312, 'hash': 'afb4e456d5c4ebdadb6a99f3d17c8b6ae64e790d8844e51627f0c8a3bd2d12ff', 'tx_count': 1}, {'index': 3217421, 'hash': '61237be5797896064b6a9a3aeec92c452b8f8be040701ea7ad8934cf5ccd308b', 'tx_count': 4}, {'index': 1482096, 'hash': '9969d5628aff464ec7adcd90318f60ea62c7507e788c8a5fd98b347dcd7e86a0', 'tx_count': 4}], + "heavy": [{'index': 1356056, 'hash': 'cbfebcce9fb58bd60c72dba37c1f32a2c9b19e587d3b7d48e303069dd9e4eef3', 'tx_count': 131}, {'index': 283411, 'hash': '561be268047239116824e15c01f544a9aa09827e97c853fccc786bd3036edb86', 'tx_count': 327}, {'index': 848536, 'hash': 'd4d213b287b554196c18d8c1e709983a13c3b289f5abf5377b00b19a21f52a17', 'tx_count': 157}, {'index': 3484522, 'hash': 'eee23e2ee6f3acc593aba3781d37ee170e16b2dd22cfbac8937e783d535d783e', 'tx_count': 392}, {'index': 2389912, 'hash': 'd1fa388224ee731705a6a3bcb9df5eb42ca852ee9b8d0de4b4f1dd2178062672', 'tx_count': 114}], +} + +# Transactions categorized by complexity (inputs/outputs count) +TRANSACTIONS = { + "small": [{'hash': '0ce73cda8dfa403f1202e515d9c69ab4b4d9b03c3c2e4b4b37be05cdc0052c53', 'block_index': 2049832, 'block_hash': 'c49ffa8a588ab47302a9e92927e4967f1dc83af1ef20483265ce351bda17142b', 'input_count': 2, 'output_count': 2}, {'hash': 'ca0cfd116a77fedc97f6bd77acf24b4fada009211f2c5788030764dab841ebcd', 'block_index': 722647, 'block_hash': '9354fe96cb86d4ecd1687069ac2fe0c56c2f73e3490b0232f931941b87c2fee5', 'input_count': 1, 'output_count': 2}, {'hash': '327ffc57f1bfcfa96cd2973798d6d05f70219d8edecb60309783c387f5480510', 'block_index': 3274697, 'block_hash': '5c60267f837227234d74b4c148b4cc251754531a4dbb5756be4ffd7a465c6fea', 'input_count': 1, 'output_count': 2}, {'hash': '2d61a6f3740498625bca522d1d399d5a9844a586ada5702f3012eb13afcdb83a', 'block_index': 1095633, 'block_hash': '8eb28a265d30873df02eed4158f7e0416e33815236b2ffa92b670d0b89717434', 'input_count': 2, 'output_count': 2}, {'hash': '23b317197dce3948099a87344aa87029fd32e32d491b43b7ed244d1e431e317b', 'block_index': 271829, 'block_hash': 'e8d13e87e78cd11badb5b8c5cda163bbb8598f7f7c7117af55e093382559e715', 'input_count': 2, 'output_count': 2}, {'hash': '5936cc53f66bd3cd5ec61e5f68b3c1cda77bf4b5a70742a6c62982fe7307a8a0', 'block_index': 746670, 'block_hash': '43900524e50448f175d0fdfd8b77fd9e62920436ea1bd553414f6a416ccc980b', 'input_count': 1, 'output_count': 2}, {'hash': '3080d1049eece509054c06e1ac9336bd5e57ca94028d6efea70b3e943737726e', 'block_index': 502548, 'block_hash': '9564d870532f1b7c745993623aa18febebb4cb8917a956375dca9596c8209d42', 'input_count': 1, 'output_count': 2}, {'hash': '77d99a7a87f888419d928510937d8be35201d897bb6fd260c0799a461bb09152', 'block_index': 349539, 'block_hash': '4248374754583c87dcda29b56bbbe0eb074b21f044e8bbd4add33d776bde5359', 'input_count': 2, 'output_count': 2}, {'hash': '358d14657c8953d1d81fbbe06ff5e39d12aad18616c7dfe2a6f58e984b7accb2', 'block_index': 3441917, 'block_hash': 'e86d87840173bd2768b3925515e11dbaf48e7bfaf60ee6079ee85cdf4adc1ff2', 'input_count': 1, 'output_count': 1}, {'hash': '9b12b9b8fc682fe30c8d4eaae5816f0a129c4d17e0f1453f35be862b998e85e8', 'block_index': 2555866, 'block_hash': 'b101c6bc2db95baf1add4480a291566383c32450447b73aff47405c916ce7a65', 'input_count': 1, 'output_count': 2}], + "large": [{'hash': '72c90c2083a7a4c54d263a031093c1354646a93c76580d3489bb9b671e029954', 'block_index': 1401831, 'block_hash': 'f551b7af97c818934456c4e20d231fa00a815b0999d720b9dc4b09cb189de587', 'input_count': 10, 'output_count': 11}, {'hash': 'edc8c6c95042f6a0d4dcca29bbeeb1930db51aaf749962f0f986c75e86555f11', 'block_index': 2866803, 'block_hash': '659d30bf36192460877e82babb48ca4e6cbc2a1440bbe1f288053e7a51a1e34e', 'input_count': 1, 'output_count': 31}, {'hash': 'e73252dae7f6f4e5342c6ecf2d9024b20e3d901522d7b9abbb7f1f600d0e5b3c', 'block_index': 698109, 'block_hash': '25b6b24f5910d2d325d8083e229c4fd9b97067e24f99847084149aa48996094f', 'input_count': 19, 'output_count': 32}, {'hash': 'c802cc5b3db2b5be0deb8474afe01ee833ca5d47dac7074646e9025666a45334', 'block_index': 275337, 'block_hash': '72af29bb833a6c0f6a12ab8f67f0448eb72043405ff5c70a3d0c2cc26b145152', 'input_count': 1, 'output_count': 13}, {'hash': '962571f8123cda447756e0bf78f97ad4ee3c7b248bebd6edc8c47f182b739228', 'block_index': 3540735, 'block_hash': '3084f4c1de7ef01e99f510a0b8dae380cc957e178ee31aca30c0877b66578a76', 'input_count': 41, 'output_count': 31}, {'hash': 'e0356dc84494d9ca75e85a725d7cdba6ec156e49f48bf3099b0f92bc351859b8', 'block_index': 3470157, 'block_hash': 'fa1ccfd22d2cd88bd28ad81dba010e10c5e65ed218ded201f9c2bd6985f44ff2', 'input_count': 12, 'output_count': 16}, {'hash': '57ce2e45f8dcdf6aa968be719812a8a1c19c61ba5a34851f16265f43f4bf5d1c', 'block_index': 3540742, 'block_hash': 'e9da1891e4b796156da479ad367c3611ae28e6e44fda4a88dad0821a7012ddd7', 'input_count': 8, 'output_count': 12}, {'hash': 'be4709bc250bd5e5a179a502619f7a8c94922e57e29bb58c84d4e91b362dc513', 'block_index': 2495159, 'block_hash': 'c5eeb12af9704c6ad15198d6b30bfec0ec9a78082ac548d46dd1be26ebfd8e27', 'input_count': 2, 'output_count': 30}, {'hash': '86f04a63d814a9c5ad469dc871a2110fe4fae251abeca2dd1423ac61eb3b3256', 'block_index': 4114317, 'block_hash': '5dd213795edf8d6b13e9e1fbb561d86097356f5b25bac4431fbb98d1cae03efa', 'input_count': 1, 'output_count': 101}, {'hash': '7a9ee97946a81fcb2f672b43096af6a237fa533abbda62e617799b66418079d7', 'block_index': 633692, 'block_hash': '9e986012a2095e09ffc69e5e19a51c1df02bb098bfaa56a90657ebbcfb75bf23', 'input_count': 37, 'output_count': 36}], +} + +# Construction metadata test cases +CONSTRUCTION_METADATA = { + "small_tx": [ + {"transaction_size": 500, "relative_ttl": 1000}, + {"transaction_size": 800, "relative_ttl": 1500}, + ], + "large_tx": [ + {"transaction_size": 15000, "relative_ttl": 3600}, + {"transaction_size": 20000, "relative_ttl": 7200}, + ], +} + +# Weights control the distribution of requests across categories +CATEGORY_WEIGHTS = { + "address_light": 0.7, + "address_medium": 0.2, + "address_heavy": 0.1, + + "block_light": 0.8, + "block_heavy": 0.2, + + "tx_small": 0.7, + "tx_large": 0.3, + + "construction_small": 0.6, + "construction_large": 0.4, +} diff --git a/tests/load-tests/uv.lock b/tests/load-tests/uv.lock new file mode 100644 index 0000000000..0cdb6306fa --- /dev/null +++ b/tests/load-tests/uv.lock @@ -0,0 +1,932 @@ +version = 1 +revision = 1 +requires-python = ">=3.12" + +[[package]] +name = "bidict" +version = "0.23.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/026678aa5a830e07cd9498a05d3e7e650a4f56a42f267a53d22bcda1bdc9/bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71", size = 29093 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764 }, +] + +[[package]] +name = "blinker" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 }, +] + +[[package]] +name = "brotli" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz", hash = "sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a", size = 7388632 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/ee/b0a11ab2315c69bb9b45a2aaed022499c9c24a205c3a49c3513b541a7967/brotli-1.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:35d382625778834a7f3061b15423919aa03e4f5da34ac8e02c074e4b75ab4f84", size = 861543 }, + { url = "https://files.pythonhosted.org/packages/e1/2f/29c1459513cd35828e25531ebfcbf3e92a5e49f560b1777a9af7203eb46e/brotli-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a61c06b334bd99bc5ae84f1eeb36bfe01400264b3c352f968c6e30a10f9d08b", size = 444288 }, + { url = "https://files.pythonhosted.org/packages/3d/6f/feba03130d5fceadfa3a1bb102cb14650798c848b1df2a808356f939bb16/brotli-1.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:acec55bb7c90f1dfc476126f9711a8e81c9af7fb617409a9ee2953115343f08d", size = 1528071 }, + { url = "https://files.pythonhosted.org/packages/2b/38/f3abb554eee089bd15471057ba85f47e53a44a462cfce265d9bf7088eb09/brotli-1.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:260d3692396e1895c5034f204f0db022c056f9e2ac841593a4cf9426e2a3faca", size = 1626913 }, + { url = "https://files.pythonhosted.org/packages/03/a7/03aa61fbc3c5cbf99b44d158665f9b0dd3d8059be16c460208d9e385c837/brotli-1.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:072e7624b1fc4d601036ab3f4f27942ef772887e876beff0301d261210bca97f", size = 1419762 }, + { url = "https://files.pythonhosted.org/packages/21/1b/0374a89ee27d152a5069c356c96b93afd1b94eae83f1e004b57eb6ce2f10/brotli-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adedc4a67e15327dfdd04884873c6d5a01d3e3b6f61406f99b1ed4865a2f6d28", size = 1484494 }, + { url = "https://files.pythonhosted.org/packages/cf/57/69d4fe84a67aef4f524dcd075c6eee868d7850e85bf01d778a857d8dbe0a/brotli-1.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7a47ce5c2288702e09dc22a44d0ee6152f2c7eda97b3c8482d826a1f3cfc7da7", size = 1593302 }, + { url = "https://files.pythonhosted.org/packages/d5/3b/39e13ce78a8e9a621c5df3aeb5fd181fcc8caba8c48a194cd629771f6828/brotli-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:af43b8711a8264bb4e7d6d9a6d004c3a2019c04c01127a868709ec29962b6036", size = 1487913 }, + { url = "https://files.pythonhosted.org/packages/62/28/4d00cb9bd76a6357a66fcd54b4b6d70288385584063f4b07884c1e7286ac/brotli-1.2.0-cp312-cp312-win32.whl", hash = "sha256:e99befa0b48f3cd293dafeacdd0d191804d105d279e0b387a32054c1180f3161", size = 334362 }, + { url = "https://files.pythonhosted.org/packages/1c/4e/bc1dcac9498859d5e353c9b153627a3752868a9d5f05ce8dedd81a2354ab/brotli-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b35c13ce241abdd44cb8ca70683f20c0c079728a36a996297adb5334adfc1c44", size = 369115 }, + { url = "https://files.pythonhosted.org/packages/6c/d4/4ad5432ac98c73096159d9ce7ffeb82d151c2ac84adcc6168e476bb54674/brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9e5825ba2c9998375530504578fd4d5d1059d09621a02065d1b6bfc41a8e05ab", size = 861523 }, + { url = "https://files.pythonhosted.org/packages/91/9f/9cc5bd03ee68a85dc4bc89114f7067c056a3c14b3d95f171918c088bf88d/brotli-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0cf8c3b8ba93d496b2fae778039e2f5ecc7cff99df84df337ca31d8f2252896c", size = 444289 }, + { url = "https://files.pythonhosted.org/packages/2e/b6/fe84227c56a865d16a6614e2c4722864b380cb14b13f3e6bef441e73a85a/brotli-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8565e3cdc1808b1a34714b553b262c5de5fbda202285782173ec137fd13709f", size = 1528076 }, + { url = "https://files.pythonhosted.org/packages/55/de/de4ae0aaca06c790371cf6e7ee93a024f6b4bb0568727da8c3de112e726c/brotli-1.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:26e8d3ecb0ee458a9804f47f21b74845cc823fd1bb19f02272be70774f56e2a6", size = 1626880 }, + { url = "https://files.pythonhosted.org/packages/5f/16/a1b22cbea436642e071adcaf8d4b350a2ad02f5e0ad0da879a1be16188a0/brotli-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67a91c5187e1eec76a61625c77a6c8c785650f5b576ca732bd33ef58b0dff49c", size = 1419737 }, + { url = "https://files.pythonhosted.org/packages/46/63/c968a97cbb3bdbf7f974ef5a6ab467a2879b82afbc5ffb65b8acbb744f95/brotli-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ecdb3b6dc36e6d6e14d3a1bdc6c1057c8cbf80db04031d566eb6080ce283a48", size = 1484440 }, + { url = "https://files.pythonhosted.org/packages/06/9d/102c67ea5c9fc171f423e8399e585dabea29b5bc79b05572891e70013cdd/brotli-1.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3e1b35d56856f3ed326b140d3c6d9db91740f22e14b06e840fe4bb1923439a18", size = 1593313 }, + { url = "https://files.pythonhosted.org/packages/9e/4a/9526d14fa6b87bc827ba1755a8440e214ff90de03095cacd78a64abe2b7d/brotli-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54a50a9dad16b32136b2241ddea9e4df159b41247b2ce6aac0b3276a66a8f1e5", size = 1487945 }, + { url = "https://files.pythonhosted.org/packages/5b/e8/3fe1ffed70cbef83c5236166acaed7bb9c766509b157854c80e2f766b38c/brotli-1.2.0-cp313-cp313-win32.whl", hash = "sha256:1b1d6a4efedd53671c793be6dd760fcf2107da3a52331ad9ea429edf0902f27a", size = 334368 }, + { url = "https://files.pythonhosted.org/packages/ff/91/e739587be970a113b37b821eae8097aac5a48e5f0eca438c22e4c7dd8648/brotli-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:b63daa43d82f0cdabf98dee215b375b4058cce72871fd07934f179885aad16e8", size = 369116 }, + { url = "https://files.pythonhosted.org/packages/17/e1/298c2ddf786bb7347a1cd71d63a347a79e5712a7c0cba9e3c3458ebd976f/brotli-1.2.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6c12dad5cd04530323e723787ff762bac749a7b256a5bece32b2243dd5c27b21", size = 863080 }, + { url = "https://files.pythonhosted.org/packages/84/0c/aac98e286ba66868b2b3b50338ffbd85a35c7122e9531a73a37a29763d38/brotli-1.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3219bd9e69868e57183316ee19c84e03e8f8b5a1d1f2667e1aa8c2f91cb061ac", size = 445453 }, + { url = "https://files.pythonhosted.org/packages/ec/f1/0ca1f3f99ae300372635ab3fe2f7a79fa335fee3d874fa7f9e68575e0e62/brotli-1.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:963a08f3bebd8b75ac57661045402da15991468a621f014be54e50f53a58d19e", size = 1528168 }, + { url = "https://files.pythonhosted.org/packages/d6/a6/2ebfc8f766d46df8d3e65b880a2e220732395e6d7dc312c1e1244b0f074a/brotli-1.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9322b9f8656782414b37e6af884146869d46ab85158201d82bab9abbcb971dc7", size = 1627098 }, + { url = "https://files.pythonhosted.org/packages/f3/2f/0976d5b097ff8a22163b10617f76b2557f15f0f39d6a0fe1f02b1a53e92b/brotli-1.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cf9cba6f5b78a2071ec6fb1e7bd39acf35071d90a81231d67e92d637776a6a63", size = 1419861 }, + { url = "https://files.pythonhosted.org/packages/9c/97/d76df7176a2ce7616ff94c1fb72d307c9a30d2189fe877f3dd99af00ea5a/brotli-1.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7547369c4392b47d30a3467fe8c3330b4f2e0f7730e45e3103d7d636678a808b", size = 1484594 }, + { url = "https://files.pythonhosted.org/packages/d3/93/14cf0b1216f43df5609f5b272050b0abd219e0b54ea80b47cef9867b45e7/brotli-1.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1530af5c3c275b8524f2e24841cbe2599d74462455e9bae5109e9ff42e9361", size = 1593455 }, + { url = "https://files.pythonhosted.org/packages/b3/73/3183c9e41ca755713bdf2cc1d0810df742c09484e2e1ddd693bee53877c1/brotli-1.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2d085ded05278d1c7f65560aae97b3160aeb2ea2c0b3e26204856beccb60888", size = 1488164 }, + { url = "https://files.pythonhosted.org/packages/64/6a/0c78d8f3a582859236482fd9fa86a65a60328a00983006bcf6d83b7b2253/brotli-1.2.0-cp314-cp314-win32.whl", hash = "sha256:832c115a020e463c2f67664560449a7bea26b0c1fdd690352addad6d0a08714d", size = 339280 }, + { url = "https://files.pythonhosted.org/packages/f5/10/56978295c14794b2c12007b07f3e41ba26acda9257457d7085b0bb3bb90c/brotli-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e7c0af964e0b4e3412a0ebf341ea26ec767fa0b4cf81abb5e897c9338b5ad6a3", size = 375639 }, +] + +[[package]] +name = "certifi" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438 }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271 }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048 }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529 }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097 }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983 }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519 }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572 }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963 }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361 }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932 }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557 }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762 }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230 }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043 }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446 }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101 }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948 }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422 }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499 }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928 }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302 }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909 }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402 }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780 }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320 }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487 }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049 }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793 }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300 }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244 }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828 }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926 }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328 }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650 }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687 }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773 }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013 }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593 }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354 }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480 }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584 }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443 }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437 }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487 }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726 }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425 }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162 }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558 }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497 }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240 }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471 }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864 }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647 }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110 }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839 }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667 }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535 }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816 }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694 }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131 }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390 }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091 }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936 }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180 }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346 }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874 }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076 }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601 }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376 }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825 }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583 }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366 }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300 }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465 }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404 }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092 }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408 }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746 }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889 }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641 }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779 }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035 }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542 }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524 }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395 }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680 }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045 }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687 }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014 }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044 }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940 }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104 }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743 }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402 }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "configargparse" +version = "1.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/85/4d/6c9ef746dfcc2a32e26f3860bb4a011c008c392b83eabdfb598d1a8bbe5d/configargparse-1.7.1.tar.gz", hash = "sha256:79c2ddae836a1e5914b71d58e4b9adbd9f7779d4e6351a637b7d2d9b6c46d3d9", size = 43958 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/28/d28211d29bcc3620b1fece85a65ce5bb22f18670a03cd28ea4b75ede270c/configargparse-1.7.1-py3-none-any.whl", hash = "sha256:8b586a31f9d873abd1ca527ffbe58863c99f36d896e2829779803125e83be4b6", size = 25607 }, +] + +[[package]] +name = "flask" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "blinker" }, + { name = "click" }, + { name = "itsdangerous" }, + { name = "jinja2" }, + { name = "markupsafe" }, + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/6d/cfe3c0fcc5e477df242b98bfe186a4c34357b4847e87ecaef04507332dab/flask-3.1.2.tar.gz", hash = "sha256:bf656c15c80190ed628ad08cdfd3aaa35beb087855e2f494910aa3774cc4fd87", size = 720160 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/f9/7f9263c5695f4bd0023734af91bedb2ff8209e8de6ead162f35d8dc762fd/flask-3.1.2-py3-none-any.whl", hash = "sha256:ca1d8112ec8a6158cc29ea4858963350011b5c846a414cdb7a954aa9e967d03c", size = 103308 }, +] + +[[package]] +name = "flask-cors" +version = "6.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flask" }, + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/37/bcfa6c7d5eec777c4c7cf45ce6b27631cebe5230caf88d85eadd63edd37a/flask_cors-6.0.1.tar.gz", hash = "sha256:d81bcb31f07b0985be7f48406247e9243aced229b7747219160a0559edd678db", size = 13463 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/f8/01bf35a3afd734345528f98d0353f2a978a476528ad4d7e78b70c4d149dd/flask_cors-6.0.1-py3-none-any.whl", hash = "sha256:c7b2cbfb1a31aa0d2e5341eea03a6805349f7a61647daee1a15c46bbe981494c", size = 13244 }, +] + +[[package]] +name = "flask-login" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flask" }, + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/6e/2f4e13e373bb49e68c02c51ceadd22d172715a06716f9299d9df01b6ddb2/Flask-Login-0.6.3.tar.gz", hash = "sha256:5e23d14a607ef12806c699590b89d0f0e0d67baeec599d75947bf9c147330333", size = 48834 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl", hash = "sha256:849b25b82a436bf830a054e74214074af59097171562ab10bfa999e6b78aae5d", size = 17303 }, +] + +[[package]] +name = "gevent" +version = "25.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, + { name = "greenlet", marker = "platform_python_implementation == 'CPython'" }, + { name = "zope-event" }, + { name = "zope-interface" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/48/b3ef2673ffb940f980966694e40d6d32560f3ffa284ecaeb5ea3a90a6d3f/gevent-25.9.1.tar.gz", hash = "sha256:adf9cd552de44a4e6754c51ff2e78d9193b7fa6eab123db9578a210e657235dd", size = 5059025 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/49/e55930ba5259629eb28ac7ee1abbca971996a9165f902f0249b561602f24/gevent-25.9.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:46b188248c84ffdec18a686fcac5dbb32365d76912e14fda350db5dc0bfd4f86", size = 2955991 }, + { url = "https://files.pythonhosted.org/packages/aa/88/63dc9e903980e1da1e16541ec5c70f2b224ec0a8e34088cb42794f1c7f52/gevent-25.9.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f2b54ea3ca6f0c763281cd3f96010ac7e98c2e267feb1221b5a26e2ca0b9a692", size = 1808503 }, + { url = "https://files.pythonhosted.org/packages/7a/8d/7236c3a8f6ef7e94c22e658397009596fa90f24c7d19da11ad7ab3a9248e/gevent-25.9.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7a834804ac00ed8a92a69d3826342c677be651b1c3cd66cc35df8bc711057aa2", size = 1890001 }, + { url = "https://files.pythonhosted.org/packages/4f/63/0d7f38c4a2085ecce26b50492fc6161aa67250d381e26d6a7322c309b00f/gevent-25.9.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:323a27192ec4da6b22a9e51c3d9d896ff20bc53fdc9e45e56eaab76d1c39dd74", size = 1855335 }, + { url = "https://files.pythonhosted.org/packages/95/18/da5211dfc54c7a57e7432fd9a6ffeae1ce36fe5a313fa782b1c96529ea3d/gevent-25.9.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6ea78b39a2c51d47ff0f130f4c755a9a4bbb2dd9721149420ad4712743911a51", size = 2109046 }, + { url = "https://files.pythonhosted.org/packages/a6/5a/7bb5ec8e43a2c6444853c4a9f955f3e72f479d7c24ea86c95fb264a2de65/gevent-25.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:dc45cd3e1cc07514a419960af932a62eb8515552ed004e56755e4bf20bad30c5", size = 1827099 }, + { url = "https://files.pythonhosted.org/packages/ca/d4/b63a0a60635470d7d986ef19897e893c15326dd69e8fb342c76a4f07fe9e/gevent-25.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34e01e50c71eaf67e92c186ee0196a039d6e4f4b35670396baed4a2d8f1b347f", size = 2172623 }, + { url = "https://files.pythonhosted.org/packages/d5/98/caf06d5d22a7c129c1fb2fc1477306902a2c8ddfd399cd26bbbd4caf2141/gevent-25.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:4acd6bcd5feabf22c7c5174bd3b9535ee9f088d2bbce789f740ad8d6554b18f3", size = 1682837 }, + { url = "https://files.pythonhosted.org/packages/5a/77/b97f086388f87f8ad3e01364f845004aef0123d4430241c7c9b1f9bde742/gevent-25.9.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:4f84591d13845ee31c13f44bdf6bd6c3dbf385b5af98b2f25ec328213775f2ed", size = 2973739 }, + { url = "https://files.pythonhosted.org/packages/3c/2e/9d5f204ead343e5b27bbb2fedaec7cd0009d50696b2266f590ae845d0331/gevent-25.9.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9cdbb24c276a2d0110ad5c978e49daf620b153719ac8a548ce1250a7eb1b9245", size = 1809165 }, + { url = "https://files.pythonhosted.org/packages/10/3e/791d1bf1eb47748606d5f2c2aa66571f474d63e0176228b1f1fd7b77ab37/gevent-25.9.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:88b6c07169468af631dcf0fdd3658f9246d6822cc51461d43f7c44f28b0abb82", size = 1890638 }, + { url = "https://files.pythonhosted.org/packages/f2/5c/9ad0229b2b4d81249ca41e4f91dd8057deaa0da6d4fbe40bf13cdc5f7a47/gevent-25.9.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b7bb0e29a7b3e6ca9bed2394aa820244069982c36dc30b70eb1004dd67851a48", size = 1857118 }, + { url = "https://files.pythonhosted.org/packages/49/2a/3010ed6c44179a3a5c5c152e6de43a30ff8bc2c8de3115ad8733533a018f/gevent-25.9.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2951bb070c0ee37b632ac9134e4fdaad70d2e660c931bb792983a0837fe5b7d7", size = 2111598 }, + { url = "https://files.pythonhosted.org/packages/08/75/6bbe57c19a7aa4527cc0f9afcdf5a5f2aed2603b08aadbccb5bf7f607ff4/gevent-25.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e4e17c2d57e9a42e25f2a73d297b22b60b2470a74be5a515b36c984e1a246d47", size = 1829059 }, + { url = "https://files.pythonhosted.org/packages/06/6e/19a9bee9092be45679cb69e4dd2e0bf5f897b7140b4b39c57cc123d24829/gevent-25.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d94936f8f8b23d9de2251798fcb603b84f083fdf0d7f427183c1828fb64f117", size = 2173529 }, + { url = "https://files.pythonhosted.org/packages/ca/4f/50de9afd879440e25737e63f5ba6ee764b75a3abe17376496ab57f432546/gevent-25.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:eb51c5f9537b07da673258b4832f6635014fee31690c3f0944d34741b69f92fa", size = 1681518 }, + { url = "https://files.pythonhosted.org/packages/15/1a/948f8167b2cdce573cf01cec07afc64d0456dc134b07900b26ac7018b37e/gevent-25.9.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:1a3fe4ea1c312dbf6b375b416925036fe79a40054e6bf6248ee46526ea628be1", size = 2982934 }, + { url = "https://files.pythonhosted.org/packages/9b/ec/726b146d1d3aad82e03d2e1e1507048ab6072f906e83f97f40667866e582/gevent-25.9.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0adb937f13e5fb90cca2edf66d8d7e99d62a299687400ce2edee3f3504009356", size = 1813982 }, + { url = "https://files.pythonhosted.org/packages/35/5d/5f83f17162301662bd1ce702f8a736a8a8cac7b7a35e1d8b9866938d1f9d/gevent-25.9.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:427f869a2050a4202d93cf7fd6ab5cffb06d3e9113c10c967b6e2a0d45237cb8", size = 1894902 }, + { url = "https://files.pythonhosted.org/packages/83/cd/cf5e74e353f60dab357829069ffc300a7bb414c761f52cf8c0c6e9728b8d/gevent-25.9.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c049880175e8c93124188f9d926af0a62826a3b81aa6d3074928345f8238279e", size = 1861792 }, + { url = "https://files.pythonhosted.org/packages/dd/65/b9a4526d4a4edce26fe4b3b993914ec9dc64baabad625a3101e51adb17f3/gevent-25.9.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b5a67a0974ad9f24721034d1e008856111e0535f1541499f72a733a73d658d1c", size = 2113215 }, + { url = "https://files.pythonhosted.org/packages/e5/be/7d35731dfaf8370795b606e515d964a0967e129db76ea7873f552045dd39/gevent-25.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1d0f5d8d73f97e24ea8d24d8be0f51e0cf7c54b8021c1fddb580bf239474690f", size = 1833449 }, + { url = "https://files.pythonhosted.org/packages/65/58/7bc52544ea5e63af88c4a26c90776feb42551b7555a1c89c20069c168a3f/gevent-25.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ddd3ff26e5c4240d3fbf5516c2d9d5f2a998ef87cfb73e1429cfaeaaec860fa6", size = 2176034 }, + { url = "https://files.pythonhosted.org/packages/c2/69/a7c4ba2ffbc7c7dbf6d8b4f5d0f0a421f7815d229f4909854266c445a3d4/gevent-25.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:bb63c0d6cb9950cc94036a4995b9cc4667b8915366613449236970f4394f94d7", size = 1703019 }, +] + +[[package]] +name = "geventhttpclient" +version = "2.3.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "brotli" }, + { name = "certifi" }, + { name = "gevent" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/6b/c9be60c4f4de31e9234d5cd927096cb44136767aa58b21ee4e3f0a60a15e/geventhttpclient-2.3.5.tar.gz", hash = "sha256:0f0cf13528de7628a21b28b80ee90a471d4840e3fe26f84b394644c366595151", size = 83673 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/6c/bef9fbdf02ffbeea0fdc5c928c0a9824e2797951b93db295ace43efbd2c5/geventhttpclient-2.3.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c262e295fa017ad7d6d62873e2a781478cb03852b1d0559ccfba598ac059fd23", size = 69745 }, + { url = "https://files.pythonhosted.org/packages/af/71/d9dfd1fd5d3ee0674942d0cdf1342001ce2c63cd95ffbd91901ace2820ab/geventhttpclient-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:44b822ce5ebddac4cd4ac4199acc2cbec1e968e3bce0ed4c62a4ce8ffaae9277", size = 51388 }, + { url = "https://files.pythonhosted.org/packages/6e/49/711a28fe4ac99537a051a1839872d740e40825be66c9c4b74d966f3554ef/geventhttpclient-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e8926ac5338764cabcf8fb54be706a6533d45756f164940a7568b03c80adb1f8", size = 51133 }, + { url = "https://files.pythonhosted.org/packages/15/6b/d1a6056deb14aff2839b11e9b1a2536b0d47f1553f7385bf83180f764210/geventhttpclient-2.3.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e84e3985a6a3f9ce39efb8fcfa4273365de2898739eea07d4b259b30ae8d58b7", size = 114985 }, + { url = "https://files.pythonhosted.org/packages/98/56/fb6b7a7c5d1b5ebe18ff9eff9f877f059231b436012c2f0498d17198f28b/geventhttpclient-2.3.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:abc63685019c5d6ec08d036248a0743df36e2afa6ab8a1fc833e2a82d0be723f", size = 115657 }, + { url = "https://files.pythonhosted.org/packages/51/8b/35068d11f81f4c928dfc188db3c1a2db92f8236ad30d2be50ef64e6f59c7/geventhttpclient-2.3.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:18e129e49ec1dadfb5fc067ac15bd43a3e6f80ddb2b6fd994ce8235c4f8b5e92", size = 121674 }, + { url = "https://files.pythonhosted.org/packages/7f/d3/3fe234574f6baf1f85784136757b5715b4636bc3576cc9b14d303949ca1d/geventhttpclient-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a04a3bdf102100a14dab58991e984b54e7db9ed950d12d8cb9fdfe5fc5088f0", size = 111577 }, + { url = "https://files.pythonhosted.org/packages/b7/e8/186b62f2774b5bb33b08576a8094b7bce1145553df9843cfb86ad10fe301/geventhttpclient-2.3.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3ecaea089408add812a7c1ad9c6043741155f4fbe5ed5c1741ce9322044f419d", size = 118453 }, + { url = "https://files.pythonhosted.org/packages/e6/b2/3374065e10242c3013dc8a5973abd7c1514cd013a3f40b28a40de4070849/geventhttpclient-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:47fa4d0b9f1739570960b5125e5c86974dff8baaa245d3b96f3e214efbb3ae5e", size = 112226 }, + { url = "https://files.pythonhosted.org/packages/84/d9/ea4ed02204c84888acae2d834cf09e165388ee450ec90fc0deed6106dce0/geventhttpclient-2.3.5-cp312-cp312-win32.whl", hash = "sha256:677be43d1941543d2897123b98831867a48286c12cd378ad995f545442854558", size = 48360 }, + { url = "https://files.pythonhosted.org/packages/ec/75/7686abde7a8b2b83040a306339558b6964ebfad66ff5b83c83a4a0aaa8a7/geventhttpclient-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:cee0ce8bb23668fb6b1a2cc572cb3d01765c5d95734c5d205e1ff459708e4c19", size = 48994 }, + { url = "https://files.pythonhosted.org/packages/8d/a7/bdcb92b4d6240538eaf7194bde4a086607a86061e31acbd4c065958e52ea/geventhttpclient-2.3.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:700d28d00d77e3c32d9e65dc078ee52a5ca77c3ac16f55674ae36250fe2550a1", size = 69750 }, + { url = "https://files.pythonhosted.org/packages/59/19/91d9c585a5c3221882bc372de19885c14b04534895e68ebc8fd66a897a3c/geventhttpclient-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9a0c0d37fc2bc60dea9d66e839c497374a5c15ec45523ae358593c760a5d433e", size = 51392 }, + { url = "https://files.pythonhosted.org/packages/c5/30/2297177c2a5d6fde7345ff44543afb61ede37eb4b9f156fea8aed2593776/geventhttpclient-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c8fceda991eab2afd95c92b3e4177ce684ea8738ef15043ebc911eb7b336dc38", size = 51126 }, + { url = "https://files.pythonhosted.org/packages/9c/eb/b11c05d6864e4726795b6a4b41c30a6e6df5f3d4709e24a3db1f1c597240/geventhttpclient-2.3.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1fbc86461e993ff6e15ee33a8252bcec6aede03ce8d8640da4205112eba28d11", size = 115000 }, + { url = "https://files.pythonhosted.org/packages/ae/09/0a5efe53df27303793a2aeaf1181fde21e490bbae9bd2cdf4ea2befba867/geventhttpclient-2.3.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d8c2b55d2c3e22be8a6fa48acde4771dcdecf01309125f1d8630de8bb4daa", size = 115693 }, + { url = "https://files.pythonhosted.org/packages/0e/60/ab039a4eb2537fa0d7c70f467fa97816035b8c0556a7cd5bf830be67160a/geventhttpclient-2.3.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:006d301f98222d1649b5df7e5b475eefc79519fbaf3309c5fde606db188686c8", size = 121682 }, + { url = "https://files.pythonhosted.org/packages/5a/8b/c480772879b7b731c1bf4301da9df55bcb9c6e947d8a71ec2ba6705b39e6/geventhttpclient-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:75bd6b8131e4c566ef69df881f1861e90d00c1222e41ab211f328bec71559d75", size = 111666 }, + { url = "https://files.pythonhosted.org/packages/b9/93/b31c882d3748ca39528ce755bba243ef316803acc6a4f9157d74332bc147/geventhttpclient-2.3.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3081221440b270e535cc796b8d3d4e9c423e89a58ac825de94af5a630ea9911e", size = 118445 }, + { url = "https://files.pythonhosted.org/packages/3e/c0/3c035c26e1740fd3cf83d73b36657ed2c227a6ae4d097898127b1ae71e46/geventhttpclient-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee48b9cdde46f4c1e4609f9ba7e4a4096f0447bb5e07ddd531b3bb67461cc4e2", size = 112256 }, + { url = "https://files.pythonhosted.org/packages/62/57/d010e546212f36797090ff88df4ab38becb01749e9ed07bf9a5916305ef0/geventhttpclient-2.3.5-cp313-cp313-win32.whl", hash = "sha256:22b6bd036ce0cfe5e7a280eda17ab6358b7a0f340ed5893015f3d2575624b4a4", size = 48357 }, + { url = "https://files.pythonhosted.org/packages/9d/aa/eaeefdeec8fb35dc707be4f3fa0b0034053727aa0ce6729fe13f6ce22751/geventhttpclient-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:4d89b59ee8b672b355a598dd2a964b768c1acf9e0c3429bb8e393a9eea31dd26", size = 48986 }, + { url = "https://files.pythonhosted.org/packages/70/50/5fee5b08580997e17fb796bdde90cd6d7bdb7a971b7b736bc606370a5e49/geventhttpclient-2.3.5-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:7a5f79c9bd0a47b18e3cf58c27f9aa4e8e13fedb12f20ea494771ad4d721f053", size = 70024 }, + { url = "https://files.pythonhosted.org/packages/74/e7/c77dc7b00cd59c59b63b2bfe3c9ebf7d4583a5eabcc6e31a5b64d29cb923/geventhttpclient-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2e294e70d7c30f0209921dc1548428887923e85f28a78a3905b4a11aefb13746", size = 51515 }, + { url = "https://files.pythonhosted.org/packages/46/bb/946b17788d00e02a8ef2a1fde6c4769dacb00a2d628e6bf2f06e2991c885/geventhttpclient-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c5d8a4a57ecc9281c037544645141514a5753db6d78b2dda014f11ef639cd641", size = 51169 }, + { url = "https://files.pythonhosted.org/packages/53/90/105337fda82dd39a735042077e4e86cccca527aea4aaf9f8cf65c0dc2416/geventhttpclient-2.3.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:18f1a02a1f51731e7433876be07859c8b1ccfd826e79ce7db03a54a1c64c9cb3", size = 115034 }, + { url = "https://files.pythonhosted.org/packages/d2/ef/3dea5e1f08c8e02769dd9facd9606b1c77d697d73e69feec856c5c708823/geventhttpclient-2.3.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4024739fd05b193b233e084014ee9d87f49cbeb24727d4adf23698417f6fff13", size = 115760 }, + { url = "https://files.pythonhosted.org/packages/e0/4c/9a32a96636aadec1c043fdefbf4b0150b532b3df9f02afb3a66d008f222c/geventhttpclient-2.3.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4cabd19028ccbfa5871d550f627c7b9e163de99f7ad80d451ffcbeee6fb427d9", size = 121757 }, + { url = "https://files.pythonhosted.org/packages/15/83/7d491256c1cfe9208ffa0ee7780699918b5b24d5336f719e17a4909df8be/geventhttpclient-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:228e639471ed636a7ea46b17fdd207da34f3519e6f84da30b510673ddf2fe2a6", size = 111747 }, + { url = "https://files.pythonhosted.org/packages/c0/27/5fdc2b47a3975d050a665c1f8562bcaf6e2cf5fc92d56ee1f4ec9ec48210/geventhttpclient-2.3.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ac0d3da9228f53f7a4960619172a6b6c11e0b3e8a470903166d83af66bfc8ce6", size = 118489 }, + { url = "https://files.pythonhosted.org/packages/d3/e0/704fa92777563f24beebee63567b0e04601e13ae171764dc67c7da5a8f2c/geventhttpclient-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d84c96d8b83c5e9b9059e4f2f62917eed834519c00b61d820b2d6aaefb4012a2", size = 112198 }, + { url = "https://files.pythonhosted.org/packages/16/6f/ac0e5d6b51a03183ee171ba3d4fd3cbfed7284d3dceaef37b6c209a67597/geventhttpclient-2.3.5-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:849bd108028ae0fc24ed65ca8e693c8d4ac140ecffa394e69fc77203c4dd93a2", size = 70417 }, + { url = "https://files.pythonhosted.org/packages/09/ca/6c3de521fd84a52505269ca2afd713d5d72d04badb0a27cbd2a4964d39ff/geventhttpclient-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:3c412be766aced0bec5d4a7b12a499bc8619a6d692ac2f6df7b8062de26f724b", size = 51695 }, + { url = "https://files.pythonhosted.org/packages/40/da/47413b2483b98cd9e519c76a52aa82f049cb586ee12420e9dd4f13c56d67/geventhttpclient-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:29a8efd438bf13f69bf5099e7577c44fcec8864a832b1de39c484346f0a9bf62", size = 51384 }, + { url = "https://files.pythonhosted.org/packages/02/8e/c45858e81cfe8208f41e186896403f711fd0caae3298c11c0e5d6f1638cf/geventhttpclient-2.3.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ab68459780add7b52ada0092af1a4773d0acc870373e6fd21179d9e32d23bfb", size = 117934 }, + { url = "https://files.pythonhosted.org/packages/6e/a9/ae0c4b5b50090c878eeee938747e3cae94776ac066fee35ca2bc51f146bc/geventhttpclient-2.3.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:966ec7a7948adbf2dc5f68d76119d29f05e0c1f645c0d516a5ddb35f9e5d3242", size = 119584 }, + { url = "https://files.pythonhosted.org/packages/9d/a5/82bff95f26d4fda52a9279142a47fcf49bc3a70b2489a55cf609481d0081/geventhttpclient-2.3.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:693d8fea804cd2547b9cc9bab13c73f9394b912391ab6e34ea3719a1a875e58c", size = 125389 }, + { url = "https://files.pythonhosted.org/packages/29/24/445a824edd51e43bfd81fa03f91b91580540592f312237c21a75c97e2fa4/geventhttpclient-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac03db48b1e0e913b3becd1e5fb2b52453754172be6868e067787f72cd1158ed", size = 115216 }, + { url = "https://files.pythonhosted.org/packages/49/d8/ef1c37860cc8f0f5d7ce8086bf385818fcc5e8e44c1fe4aad3783c34eaef/geventhttpclient-2.3.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:79e2afab2ec6562bb3814bdac6bb04333f3c6ab4824666565a73f73caf91d8fd", size = 121867 }, + { url = "https://files.pythonhosted.org/packages/7a/50/75d5a7d123015c8cd57710fecc7c1ecdecb7a98381034c1f87ba5dfb87e4/geventhttpclient-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7803e3e2db5f2bc87743afd015b86b7250c20dc4ace68899b2510a98519d8643", size = 114998 }, +] + +[[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 } +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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484 }, +] + +[[package]] +name = "itsdangerous" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234 }, +] + +[[package]] +name = "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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, +] + +[[package]] +name = "load-tests" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "locust" }, + { name = "psycopg2-binary" }, + { name = "python-dotenv" }, +] + +[package.metadata] +requires-dist = [ + { name = "locust", specifier = ">=2.42.3" }, + { name = "psycopg2-binary", specifier = ">=2.9.11" }, + { name = "python-dotenv", specifier = ">=1.2.1" }, +] + +[[package]] +name = "locust" +version = "2.42.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "configargparse" }, + { name = "flask" }, + { name = "flask-cors" }, + { name = "flask-login" }, + { name = "gevent" }, + { name = "geventhttpclient" }, + { name = "locust-cloud" }, + { name = "msgpack" }, + { name = "psutil" }, + { name = "pytest" }, + { name = "python-engineio" }, + { name = "python-socketio", extra = ["client"] }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "pyzmq" }, + { name = "requests" }, + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/f9/ba22c81fb6fbb81610e4c661c6ffe4f495cbb5d5e8296de31964e710feb8/locust-2.42.3.tar.gz", hash = "sha256:01227890df7bf5268332f2dc041558ae45561b72a06193b068f7e02774f75ab2", size = 1416478 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/b3/38dd0eb197ca63d1ee39f6cedfb1aab8e6c844da3c8f3fd8d0f41192a293/locust-2.42.3-py3-none-any.whl", hash = "sha256:89c6359abcb79f8cbd870cd33c01acd3dc099baaea8774155cfdede4167d6a1d", size = 1435187 }, +] + +[[package]] +name = "locust-cloud" +version = "1.29.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "configargparse" }, + { name = "gevent" }, + { name = "platformdirs" }, + { name = "python-engineio" }, + { name = "python-socketio", extra = ["client"] }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5d/59/9779e5606e9580795ad1fdf45e259300a1cbd18155994e84277fa7bb2aa9/locust_cloud-1.29.0.tar.gz", hash = "sha256:2fd2465eef49253e9c39ac6f7d7ac18588159ceff9520218860de0d798581e44", size = 457177 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/1d/f2442ba26ebee956e54c84dbfe7c275d354707faf23232f0af59c71114ce/locust_cloud-1.29.0-py3-none-any.whl", hash = "sha256:abe5d1ac82f7b39d5a26e5ef8263091f12f9c0d4416b7029b12461f67e03c6ec", size = 413323 }, +] + +[[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 } +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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540 }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105 }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543 }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113 }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612 }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200 }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747 }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341 }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819 }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426 }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146 }, +] + +[[package]] +name = "msgpack" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/bd/8b0d01c756203fbab65d265859749860682ccd2a59594609aeec3a144efa/msgpack-1.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:70a0dff9d1f8da25179ffcf880e10cf1aad55fdb63cd59c9a49a1b82290062aa", size = 81939 }, + { url = "https://files.pythonhosted.org/packages/34/68/ba4f155f793a74c1483d4bdef136e1023f7bcba557f0db4ef3db3c665cf1/msgpack-1.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:446abdd8b94b55c800ac34b102dffd2f6aa0ce643c55dfc017ad89347db3dbdb", size = 85064 }, + { url = "https://files.pythonhosted.org/packages/f2/60/a064b0345fc36c4c3d2c743c82d9100c40388d77f0b48b2f04d6041dbec1/msgpack-1.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c63eea553c69ab05b6747901b97d620bb2a690633c77f23feb0c6a947a8a7b8f", size = 417131 }, + { url = "https://files.pythonhosted.org/packages/65/92/a5100f7185a800a5d29f8d14041f61475b9de465ffcc0f3b9fba606e4505/msgpack-1.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:372839311ccf6bdaf39b00b61288e0557916c3729529b301c52c2d88842add42", size = 427556 }, + { url = "https://files.pythonhosted.org/packages/f5/87/ffe21d1bf7d9991354ad93949286f643b2bb6ddbeab66373922b44c3b8cc/msgpack-1.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2929af52106ca73fcb28576218476ffbb531a036c2adbcf54a3664de124303e9", size = 404920 }, + { url = "https://files.pythonhosted.org/packages/ff/41/8543ed2b8604f7c0d89ce066f42007faac1eaa7d79a81555f206a5cdb889/msgpack-1.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be52a8fc79e45b0364210eef5234a7cf8d330836d0a64dfbb878efa903d84620", size = 415013 }, + { url = "https://files.pythonhosted.org/packages/41/0d/2ddfaa8b7e1cee6c490d46cb0a39742b19e2481600a7a0e96537e9c22f43/msgpack-1.1.2-cp312-cp312-win32.whl", hash = "sha256:1fff3d825d7859ac888b0fbda39a42d59193543920eda9d9bea44d958a878029", size = 65096 }, + { url = "https://files.pythonhosted.org/packages/8c/ec/d431eb7941fb55a31dd6ca3404d41fbb52d99172df2e7707754488390910/msgpack-1.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1de460f0403172cff81169a30b9a92b260cb809c4cb7e2fc79ae8d0510c78b6b", size = 72708 }, + { url = "https://files.pythonhosted.org/packages/c5/31/5b1a1f70eb0e87d1678e9624908f86317787b536060641d6798e3cf70ace/msgpack-1.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:be5980f3ee0e6bd44f3a9e9dea01054f175b50c3e6cdb692bc9424c0bbb8bf69", size = 64119 }, + { url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212 }, + { url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315 }, + { url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721 }, + { url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657 }, + { url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668 }, + { url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040 }, + { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037 }, + { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631 }, + { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118 }, + { url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127 }, + { url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981 }, + { url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885 }, + { url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658 }, + { url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290 }, + { url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234 }, + { url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391 }, + { url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787 }, + { url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453 }, + { url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264 }, + { url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076 }, + { url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242 }, + { url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509 }, + { url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957 }, + { url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910 }, + { url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197 }, + { url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772 }, + { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, +] + +[[package]] +name = "psutil" +version = "7.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/88/bdd0a41e5857d5d703287598cbf08dad90aed56774ea52ae071bae9071b6/psutil-7.1.3.tar.gz", hash = "sha256:6c86281738d77335af7aec228328e944b30930899ea760ecf33a4dba66be5e74", size = 489059 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/93/0c49e776b8734fef56ec9c5c57f923922f2cf0497d62e0f419465f28f3d0/psutil-7.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0005da714eee687b4b8decd3d6cc7c6db36215c9e74e5ad2264b90c3df7d92dc", size = 239751 }, + { url = "https://files.pythonhosted.org/packages/6f/8d/b31e39c769e70780f007969815195a55c81a63efebdd4dbe9e7a113adb2f/psutil-7.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:19644c85dcb987e35eeeaefdc3915d059dac7bd1167cdcdbf27e0ce2df0c08c0", size = 240368 }, + { url = "https://files.pythonhosted.org/packages/62/61/23fd4acc3c9eebbf6b6c78bcd89e5d020cfde4acf0a9233e9d4e3fa698b4/psutil-7.1.3-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95ef04cf2e5ba0ab9eaafc4a11eaae91b44f4ef5541acd2ee91d9108d00d59a7", size = 287134 }, + { url = "https://files.pythonhosted.org/packages/30/1c/f921a009ea9ceb51aa355cb0cc118f68d354db36eae18174bab63affb3e6/psutil-7.1.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1068c303be3a72f8e18e412c5b2a8f6d31750fb152f9cb106b54090296c9d251", size = 289904 }, + { url = "https://files.pythonhosted.org/packages/a6/82/62d68066e13e46a5116df187d319d1724b3f437ddd0f958756fc052677f4/psutil-7.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:18349c5c24b06ac5612c0428ec2a0331c26443d259e2a0144a9b24b4395b58fa", size = 249642 }, + { url = "https://files.pythonhosted.org/packages/df/ad/c1cd5fe965c14a0392112f68362cfceb5230819dbb5b1888950d18a11d9f/psutil-7.1.3-cp313-cp313t-win_arm64.whl", hash = "sha256:c525ffa774fe4496282fb0b1187725793de3e7c6b29e41562733cae9ada151ee", size = 245518 }, + { url = "https://files.pythonhosted.org/packages/2e/bb/6670bded3e3236eb4287c7bcdc167e9fae6e1e9286e437f7111caed2f909/psutil-7.1.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b403da1df4d6d43973dc004d19cee3b848e998ae3154cc8097d139b77156c353", size = 239843 }, + { url = "https://files.pythonhosted.org/packages/b8/66/853d50e75a38c9a7370ddbeefabdd3d3116b9c31ef94dc92c6729bc36bec/psutil-7.1.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ad81425efc5e75da3f39b3e636293360ad8d0b49bed7df824c79764fb4ba9b8b", size = 240369 }, + { url = "https://files.pythonhosted.org/packages/41/bd/313aba97cb5bfb26916dc29cf0646cbe4dd6a89ca69e8c6edce654876d39/psutil-7.1.3-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f33a3702e167783a9213db10ad29650ebf383946e91bc77f28a5eb083496bc9", size = 288210 }, + { url = "https://files.pythonhosted.org/packages/c2/fa/76e3c06e760927a0cfb5705eb38164254de34e9bd86db656d4dbaa228b04/psutil-7.1.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fac9cd332c67f4422504297889da5ab7e05fd11e3c4392140f7370f4208ded1f", size = 291182 }, + { url = "https://files.pythonhosted.org/packages/0f/1d/5774a91607035ee5078b8fd747686ebec28a962f178712de100d00b78a32/psutil-7.1.3-cp314-cp314t-win_amd64.whl", hash = "sha256:3792983e23b69843aea49c8f5b8f115572c5ab64c153bada5270086a2123c7e7", size = 250466 }, + { url = "https://files.pythonhosted.org/packages/00/ca/e426584bacb43a5cb1ac91fae1937f478cd8fbe5e4ff96574e698a2c77cd/psutil-7.1.3-cp314-cp314t-win_arm64.whl", hash = "sha256:31d77fcedb7529f27bb3a0472bea9334349f9a04160e8e6e5020f22c59893264", size = 245756 }, + { url = "https://files.pythonhosted.org/packages/ef/94/46b9154a800253e7ecff5aaacdf8ebf43db99de4a2dfa18575b02548654e/psutil-7.1.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2bdbcd0e58ca14996a42adf3621a6244f1bb2e2e528886959c72cf1e326677ab", size = 238359 }, + { url = "https://files.pythonhosted.org/packages/68/3a/9f93cff5c025029a36d9a92fef47220ab4692ee7f2be0fba9f92813d0cb8/psutil-7.1.3-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc31fa00f1fbc3c3802141eede66f3a2d51d89716a194bf2cd6fc68310a19880", size = 239171 }, + { url = "https://files.pythonhosted.org/packages/ce/b1/5f49af514f76431ba4eea935b8ad3725cdeb397e9245ab919dbc1d1dc20f/psutil-7.1.3-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb428f9f05c1225a558f53e30ccbad9930b11c3fc206836242de1091d3e7dd3", size = 263261 }, + { url = "https://files.pythonhosted.org/packages/e0/95/992c8816a74016eb095e73585d747e0a8ea21a061ed3689474fabb29a395/psutil-7.1.3-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56d974e02ca2c8eb4812c3f76c30e28836fffc311d55d979f1465c1feeb2b68b", size = 264635 }, + { url = "https://files.pythonhosted.org/packages/55/4c/c3ed1a622b6ae2fd3c945a366e64eb35247a31e4db16cf5095e269e8eb3c/psutil-7.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:f39c2c19fe824b47484b96f9692932248a54c43799a84282cfe58d05a6449efd", size = 247633 }, + { url = "https://files.pythonhosted.org/packages/c9/ad/33b2ccec09bf96c2b2ef3f9a6f66baac8253d7565d8839e024a6b905d45d/psutil-7.1.3-cp37-abi3-win_arm64.whl", hash = "sha256:bd0d69cee829226a761e92f28140bec9a5ee9d5b4fb4b0cc589068dbfff559b1", size = 244608 }, +] + +[[package]] +name = "psycopg2-binary" +version = "2.9.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/6c/8767aaa597ba424643dc87348c6f1754dd9f48e80fdc1b9f7ca5c3a7c213/psycopg2-binary-2.9.11.tar.gz", hash = "sha256:b6aed9e096bf63f9e75edf2581aa9a7e7186d97ab5c177aa6c87797cd591236c", size = 379620 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/91/f870a02f51be4a65987b45a7de4c2e1897dd0d01051e2b559a38fa634e3e/psycopg2_binary-2.9.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be9b840ac0525a283a96b556616f5b4820e0526addb8dcf6525a0fa162730be4", size = 3756603 }, + { url = "https://files.pythonhosted.org/packages/27/fa/cae40e06849b6c9a95eb5c04d419942f00d9eaac8d81626107461e268821/psycopg2_binary-2.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f090b7ddd13ca842ebfe301cd587a76a4cf0913b1e429eb92c1be5dbeb1a19bc", size = 3864509 }, + { url = "https://files.pythonhosted.org/packages/2d/75/364847b879eb630b3ac8293798e380e441a957c53657995053c5ec39a316/psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ab8905b5dcb05bf3fb22e0cf90e10f469563486ffb6a96569e51f897c750a76a", size = 4411159 }, + { url = "https://files.pythonhosted.org/packages/6f/a0/567f7ea38b6e1c62aafd58375665a547c00c608a471620c0edc364733e13/psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:bf940cd7e7fec19181fdbc29d76911741153d51cab52e5c21165f3262125685e", size = 4468234 }, + { url = "https://files.pythonhosted.org/packages/30/da/4e42788fb811bbbfd7b7f045570c062f49e350e1d1f3df056c3fb5763353/psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fa0f693d3c68ae925966f0b14b8edda71696608039f4ed61b1fe9ffa468d16db", size = 4166236 }, + { url = "https://files.pythonhosted.org/packages/3c/94/c1777c355bc560992af848d98216148be5f1be001af06e06fc49cbded578/psycopg2_binary-2.9.11-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a1cf393f1cdaf6a9b57c0a719a1068ba1069f022a59b8b1fe44b006745b59757", size = 3983083 }, + { url = "https://files.pythonhosted.org/packages/bd/42/c9a21edf0e3daa7825ed04a4a8588686c6c14904344344a039556d78aa58/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7a6beb4beaa62f88592ccc65df20328029d721db309cb3250b0aae0fa146c3", size = 3652281 }, + { url = "https://files.pythonhosted.org/packages/12/22/dedfbcfa97917982301496b6b5e5e6c5531d1f35dd2b488b08d1ebc52482/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:31b32c457a6025e74d233957cc9736742ac5a6cb196c6b68499f6bb51390bd6a", size = 3298010 }, + { url = "https://files.pythonhosted.org/packages/66/ea/d3390e6696276078bd01b2ece417deac954dfdd552d2edc3d03204416c0c/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:edcb3aeb11cb4bf13a2af3c53a15b3d612edeb6409047ea0b5d6a21a9d744b34", size = 3044641 }, + { url = "https://files.pythonhosted.org/packages/12/9a/0402ded6cbd321da0c0ba7d34dc12b29b14f5764c2fc10750daa38e825fc/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b6d93d7c0b61a1dd6197d208ab613eb7dcfdcca0a49c42ceb082257991de9d", size = 3347940 }, + { url = "https://files.pythonhosted.org/packages/b1/d2/99b55e85832ccde77b211738ff3925a5d73ad183c0b37bcbbe5a8ff04978/psycopg2_binary-2.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:b33fabeb1fde21180479b2d4667e994de7bbf0eec22832ba5d9b5e4cf65b6c6d", size = 2714147 }, + { url = "https://files.pythonhosted.org/packages/ff/a8/a2709681b3ac11b0b1786def10006b8995125ba268c9a54bea6f5ae8bd3e/psycopg2_binary-2.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b8fb3db325435d34235b044b199e56cdf9ff41223a4b9752e8576465170bb38c", size = 3756572 }, + { url = "https://files.pythonhosted.org/packages/62/e1/c2b38d256d0dafd32713e9f31982a5b028f4a3651f446be70785f484f472/psycopg2_binary-2.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:366df99e710a2acd90efed3764bb1e28df6c675d33a7fb40df9b7281694432ee", size = 3864529 }, + { url = "https://files.pythonhosted.org/packages/11/32/b2ffe8f3853c181e88f0a157c5fb4e383102238d73c52ac6d93a5c8bffe6/psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c55b385daa2f92cb64b12ec4536c66954ac53654c7f15a203578da4e78105c0", size = 4411242 }, + { url = "https://files.pythonhosted.org/packages/10/04/6ca7477e6160ae258dc96f67c371157776564679aefd247b66f4661501a2/psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c0377174bf1dd416993d16edc15357f6eb17ac998244cca19bc67cdc0e2e5766", size = 4468258 }, + { url = "https://files.pythonhosted.org/packages/3c/7e/6a1a38f86412df101435809f225d57c1a021307dd0689f7a5e7fe83588b1/psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c6ff3335ce08c75afaed19e08699e8aacf95d4a260b495a4a8545244fe2ceb3", size = 4166295 }, + { url = "https://files.pythonhosted.org/packages/f2/7d/c07374c501b45f3579a9eb761cbf2604ddef3d96ad48679112c2c5aa9c25/psycopg2_binary-2.9.11-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:84011ba3109e06ac412f95399b704d3d6950e386b7994475b231cf61eec2fc1f", size = 3983133 }, + { url = "https://files.pythonhosted.org/packages/82/56/993b7104cb8345ad7d4516538ccf8f0d0ac640b1ebd8c754a7b024e76878/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba34475ceb08cccbdd98f6b46916917ae6eeb92b5ae111df10b544c3a4621dc4", size = 3652383 }, + { url = "https://files.pythonhosted.org/packages/2d/ac/eaeb6029362fd8d454a27374d84c6866c82c33bfc24587b4face5a8e43ef/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b31e90fdd0f968c2de3b26ab014314fe814225b6c324f770952f7d38abf17e3c", size = 3298168 }, + { url = "https://files.pythonhosted.org/packages/2b/39/50c3facc66bded9ada5cbc0de867499a703dc6bca6be03070b4e3b65da6c/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d526864e0f67f74937a8fce859bd56c979f5e2ec57ca7c627f5f1071ef7fee60", size = 3044712 }, + { url = "https://files.pythonhosted.org/packages/9c/8e/b7de019a1f562f72ada81081a12823d3c1590bedc48d7d2559410a2763fe/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04195548662fa544626c8ea0f06561eb6203f1984ba5b4562764fbeb4c3d14b1", size = 3347549 }, + { url = "https://files.pythonhosted.org/packages/80/2d/1bb683f64737bbb1f86c82b7359db1eb2be4e2c0c13b947f80efefa7d3e5/psycopg2_binary-2.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:efff12b432179443f54e230fdf60de1f6cc726b6c832db8701227d089310e8aa", size = 2714215 }, + { url = "https://files.pythonhosted.org/packages/64/12/93ef0098590cf51d9732b4f139533732565704f45bdc1ffa741b7c95fb54/psycopg2_binary-2.9.11-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:92e3b669236327083a2e33ccfa0d320dd01b9803b3e14dd986a4fc54aa00f4e1", size = 3756567 }, + { url = "https://files.pythonhosted.org/packages/7c/a9/9d55c614a891288f15ca4b5209b09f0f01e3124056924e17b81b9fa054cc/psycopg2_binary-2.9.11-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e0deeb03da539fa3577fcb0b3f2554a97f7e5477c246098dbb18091a4a01c16f", size = 3864755 }, + { url = "https://files.pythonhosted.org/packages/13/1e/98874ce72fd29cbde93209977b196a2edae03f8490d1bd8158e7f1daf3a0/psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b52a3f9bb540a3e4ec0f6ba6d31339727b2950c9772850d6545b7eae0b9d7c5", size = 4411646 }, + { url = "https://files.pythonhosted.org/packages/5a/bd/a335ce6645334fb8d758cc358810defca14a1d19ffbc8a10bd38a2328565/psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:db4fd476874ccfdbb630a54426964959e58da4c61c9feba73e6094d51303d7d8", size = 4468701 }, + { url = "https://files.pythonhosted.org/packages/44/d6/c8b4f53f34e295e45709b7568bf9b9407a612ea30387d35eb9fa84f269b4/psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:47f212c1d3be608a12937cc131bd85502954398aaa1320cb4c14421a0ffccf4c", size = 4166293 }, + { url = "https://files.pythonhosted.org/packages/4b/e0/f8cc36eadd1b716ab36bb290618a3292e009867e5c97ce4aba908cb99644/psycopg2_binary-2.9.11-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e35b7abae2b0adab776add56111df1735ccc71406e56203515e228a8dc07089f", size = 3983184 }, + { url = "https://files.pythonhosted.org/packages/53/3e/2a8fe18a4e61cfb3417da67b6318e12691772c0696d79434184a511906dc/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fcf21be3ce5f5659daefd2b3b3b6e4727b028221ddc94e6c1523425579664747", size = 3652650 }, + { url = "https://files.pythonhosted.org/packages/76/36/03801461b31b29fe58d228c24388f999fe814dfc302856e0d17f97d7c54d/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9bd81e64e8de111237737b29d68039b9c813bdf520156af36d26819c9a979e5f", size = 3298663 }, + { url = "https://files.pythonhosted.org/packages/97/77/21b0ea2e1a73aa5fa9222b2a6b8ba325c43c3a8d54272839c991f2345656/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:32770a4d666fbdafab017086655bcddab791d7cb260a16679cc5a7338b64343b", size = 3044737 }, + { url = "https://files.pythonhosted.org/packages/67/69/f36abe5f118c1dca6d3726ceae164b9356985805480731ac6712a63f24f0/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3cb3a676873d7506825221045bd70e0427c905b9c8ee8d6acd70cfcbd6e576d", size = 3347643 }, + { url = "https://files.pythonhosted.org/packages/e1/36/9c0c326fe3a4227953dfb29f5d0c8ae3b8eb8c1cd2967aa569f50cb3c61f/psycopg2_binary-2.9.11-cp314-cp314-win_amd64.whl", hash = "sha256:4012c9c954dfaccd28f94e84ab9f94e12df76b4afb22331b1f0d3154893a6316", size = 2803913 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750 }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230 }, +] + +[[package]] +name = "python-engineio" +version = "4.12.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "simple-websocket" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/d8/63e5535ab21dc4998ba1cfe13690ccf122883a38f025dca24d6e56c05eba/python_engineio-4.12.3.tar.gz", hash = "sha256:35633e55ec30915e7fc8f7e34ca8d73ee0c080cec8a8cd04faf2d7396f0a7a7a", size = 91910 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/f0/c5aa0a69fd9326f013110653543f36ece4913c17921f3e1dbd78e1b423ee/python_engineio-4.12.3-py3-none-any.whl", hash = "sha256:7c099abb2a27ea7ab429c04da86ab2d82698cdd6c52406cb73766fe454feb7e1", size = 59637 }, +] + +[[package]] +name = "python-socketio" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bidict" }, + { name = "python-engineio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/3f/02f5970c82285bd015ec433078bfc3275580b03715ed6024607dbe0f1966/python_socketio-5.14.3.tar.gz", hash = "sha256:cd8da5e0666e741b4be19e07882e880f57a4751d1645f92c2bc746c95f23b1eb", size = 124266 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/1a/b393a06aa6f2f6ab4a9c5c160a62d488b17d6da5cf93a67bc13a6e3239cd/python_socketio-5.14.3-py3-none-any.whl", hash = "sha256:a5208c1bbf45a8d6328d01ed67e3fa52ec8b186fd3ea44cfcfcbd120f0c71fbe", size = 79010 }, +] + +[package.optional-dependencies] +client = [ + { name = "requests" }, + { name = "websocket-client" }, +] + +[[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 }, + { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040 }, + { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102 }, + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700 }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700 }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318 }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714 }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800 }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540 }, +] + +[[package]] +name = "pyzmq" +version = "27.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279 }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645 }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574 }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995 }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070 }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121 }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550 }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184 }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480 }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993 }, + { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436 }, + { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301 }, + { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197 }, + { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275 }, + { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469 }, + { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961 }, + { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282 }, + { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468 }, + { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394 }, + { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964 }, + { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029 }, + { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541 }, + { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197 }, + { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175 }, + { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427 }, + { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929 }, + { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193 }, + { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388 }, + { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316 }, + { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472 }, + { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401 }, + { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170 }, +] + +[[package]] +name = "requests" +version = "2.32.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847 }, +] + +[[package]] +name = "simple-websocket" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wsproto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b0/d4/bfa032f961103eba93de583b161f0e6a5b63cebb8f2c7d0c6e6efe1e3d2e/simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4", size = 17300 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c", size = 13842 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795 }, +] + +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616 }, +] + +[[package]] +name = "werkzeug" +version = "3.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498 }, +] + +[[package]] +name = "wsproto" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/8d/48e227460422d3f78f52618d8ef7d7a0474c6fcdaddf7f2d1aa25854ea75/wsproto-1.3.1.tar.gz", hash = "sha256:81529992325c28f0d9b86ca66fc973da96eb80ab53410249ce2e502749c7723c", size = 50083 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/da/539c2d24b13025e54a86ce3215eb9b6297b023937a087db9ef2a436cc7b4/wsproto-1.3.1-py3-none-any.whl", hash = "sha256:297ce79322989c0d286cc158681641cd18bc7632dfb38cf4054696a89179b993", size = 24402 }, +] + +[[package]] +name = "zope-event" +version = "6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/33/d3eeac228fc14de76615612ee208be2d8a5b5b0fada36bf9b62d6b40600c/zope_event-6.1.tar.gz", hash = "sha256:6052a3e0cb8565d3d4ef1a3a7809336ac519bc4fe38398cb8d466db09adef4f0", size = 18739 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/b0/956902e5e1302f8c5d124e219c6bf214e2649f92ad5fce85b05c039a04c9/zope_event-6.1-py3-none-any.whl", hash = "sha256:0ca78b6391b694272b23ec1335c0294cc471065ed10f7f606858fc54566c25a0", size = 6414 }, +] + +[[package]] +name = "zope-interface" +version = "8.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/71/c9/5ec8679a04d37c797d343f650c51ad67d178f0001c363e44b6ac5f97a9da/zope_interface-8.1.1.tar.gz", hash = "sha256:51b10e6e8e238d719636a401f44f1e366146912407b58453936b781a19be19ec", size = 254748 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/3d/f5b8dd2512f33bfab4faba71f66f6873603d625212206dd36f12403ae4ca/zope_interface-8.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a16715808408db7252b8c1597ed9008bdad7bf378ed48eb9b0595fad4170e49d", size = 208660 }, + { url = "https://files.pythonhosted.org/packages/e5/41/c331adea9b11e05ff9ac4eb7d3032b24c36a3654ae9f2bf4ef2997048211/zope_interface-8.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce6b58752acc3352c4aa0b55bbeae2a941d61537e6afdad2467a624219025aae", size = 208851 }, + { url = "https://files.pythonhosted.org/packages/25/00/7a8019c3bb8b119c5f50f0a4869183a4b699ca004a7f87ce98382e6b364c/zope_interface-8.1.1-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:807778883d07177713136479de7fd566f9056a13aef63b686f0ab4807c6be259", size = 259292 }, + { url = "https://files.pythonhosted.org/packages/1a/fc/b70e963bf89345edffdd5d16b61e789fdc09365972b603e13785360fea6f/zope_interface-8.1.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50e5eb3b504a7d63dc25211b9298071d5b10a3eb754d6bf2f8ef06cb49f807ab", size = 264741 }, + { url = "https://files.pythonhosted.org/packages/96/fe/7d0b5c0692b283901b34847f2b2f50d805bfff4b31de4021ac9dfb516d2a/zope_interface-8.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eee6f93b2512ec9466cf30c37548fd3ed7bc4436ab29cd5943d7a0b561f14f0f", size = 264281 }, + { url = "https://files.pythonhosted.org/packages/2b/2c/a7cebede1cf2757be158bcb151fe533fa951038cfc5007c7597f9f86804b/zope_interface-8.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:80edee6116d569883c58ff8efcecac3b737733d646802036dc337aa839a5f06b", size = 212327 }, + { url = "https://files.pythonhosted.org/packages/85/81/3c3b5386ce4fba4612fd82ffb8a90d76bcfea33ca2b6399f21e94d38484f/zope_interface-8.1.1-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:84f9be6d959640de9da5d14ac1f6a89148b16da766e88db37ed17e936160b0b1", size = 209046 }, + { url = "https://files.pythonhosted.org/packages/4a/e3/32b7cb950c4c4326b3760a8e28e5d6f70ad15f852bfd8f9364b58634f74b/zope_interface-8.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:531fba91dcb97538f70cf4642a19d6574269460274e3f6004bba6fe684449c51", size = 209104 }, + { url = "https://files.pythonhosted.org/packages/a3/3d/c4c68e1752a5f5effa2c1f5eaa4fea4399433c9b058fb7000a34bfb1c447/zope_interface-8.1.1-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:fc65f5633d5a9583ee8d88d1f5de6b46cd42c62e47757cfe86be36fb7c8c4c9b", size = 259277 }, + { url = "https://files.pythonhosted.org/packages/fd/5b/cf4437b174af7591ee29bbad728f620cab5f47bd6e9c02f87d59f31a0dda/zope_interface-8.1.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:efef80ddec4d7d99618ef71bc93b88859248075ca2e1ae1c78636654d3d55533", size = 264742 }, + { url = "https://files.pythonhosted.org/packages/0b/0e/0cf77356862852d3d3e62db9aadae5419a1a7d89bf963b219745283ab5ca/zope_interface-8.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:49aad83525eca3b4747ef51117d302e891f0042b06f32aa1c7023c62642f962b", size = 264252 }, + { url = "https://files.pythonhosted.org/packages/8a/10/2af54aa88b2fa172d12364116cc40d325fedbb1877c3bb031b0da6052855/zope_interface-8.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:71cf329a21f98cb2bd9077340a589e316ac8a415cac900575a32544b3dffcb98", size = 212330 }, + { url = "https://files.pythonhosted.org/packages/b9/f5/44efbd98ba06cb937fce7a69fcd7a78c4ac7aa4e1ad2125536801376d2d0/zope_interface-8.1.1-cp314-cp314-macosx_10_9_x86_64.whl", hash = "sha256:da311e9d253991ca327601f47c4644d72359bac6950fbb22f971b24cd7850f8c", size = 209099 }, + { url = "https://files.pythonhosted.org/packages/fd/36/a19866c09c8485c36a4c6908e1dd3f8820b41c1ee333c291157cf4cf09e7/zope_interface-8.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3fb25fca0442c7fb93c4ee40b42e3e033fef2f648730c4b7ae6d43222a3e8946", size = 209240 }, + { url = "https://files.pythonhosted.org/packages/c1/28/0dbf40db772d779a4ac8d006a57ad60936d42ad4769a3d5410dcfb98f6f9/zope_interface-8.1.1-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:bac588d0742b4e35efb7c7df1dacc0397b51ed37a17d4169a38019a1cebacf0a", size = 260919 }, + { url = "https://files.pythonhosted.org/packages/72/ae/650cd4c01dd1b32c26c800b2c4d852f044552c34a56fbb74d41f569cee31/zope_interface-8.1.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d1f053d2d5e2b393e619bce1e55954885c2e63969159aa521839e719442db49", size = 264102 }, + { url = "https://files.pythonhosted.org/packages/46/f0/f534a2c34c006aa090c593cd70eaf94e259fd0786f934698d81f0534d907/zope_interface-8.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:64a1ad7f4cb17d948c6bdc525a1d60c0e567b2526feb4fa38b38f249961306b8", size = 264276 }, + { url = "https://files.pythonhosted.org/packages/5b/a8/d7e9cf03067b767e23908dbab5f6be7735d70cb4818311a248a8c4bb23cc/zope_interface-8.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:169214da1b82b7695d1a36f92d70b11166d66b6b09d03df35d150cc62ac52276", size = 212492 }, +]