diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e0c3b7f --- /dev/null +++ b/Makefile @@ -0,0 +1,49 @@ +.PHONY: $(MAKECMDGOALS) +MAKEFLAGS += --no-print-directory +## +## 🚧 DipDup developer tools +## +PACKAGE=substrateinterface +TAG=latest +SOURCE=substrateinterface test examples + + +help: ## Show this help (default) + @grep -Fh "##" $(MAKEFILE_LIST) | grep -Fv grep -F | sed -e 's/\\$$//' | sed -e 's/##//' + +## +##-- Dependencies +## + +install: ## Install dependencies + uv sync + +update: ## Update dependencies + uv lock + +## +##-- CI +## + +all: ## Run an entire CI pipeline + make format lint test + +format: ## Format with all tools + make black + +lint: ## Lint with all tools + make ruff mypy + +test: ## Run tests + COVERAGE_CORE=sysmon pytest test + +## + +black: ## Format with black + black ${SOURCE} + +ruff: ## Lint with ruff + ruff check --fix --unsafe-fixes ${SOURCE} + +mypy: ## Lint with mypy + mypy ${SOURCE} diff --git a/README.md b/README.md index ad18b3f..73459ae 100644 --- a/README.md +++ b/README.md @@ -35,13 +35,13 @@ older or runtimes under development the `ss58_format` (default 42) and other pro ### Balance information of an account ```python -result = substrate.query('System', 'Account', ['F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T']) +result = await substrate.query('System', 'Account', ['F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T']) print(result.value['data']['free']) # 635278638077956496 ``` ### Create balance transfer extrinsic ```python -call = substrate.compose_call( +call = await substrate.compose_call( call_module='Balances', call_function='transfer', call_params={ @@ -51,9 +51,9 @@ call = substrate.compose_call( ) keypair = Keypair.create_from_uri('//Alice') -extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair) +extrinsic = await substrate.create_signed_extrinsic(call=call, keypair=keypair) -receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) +receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) print(f"Extrinsic '{receipt.extrinsic_hash}' sent and included in block '{receipt.block_hash}'") ``` diff --git a/docs/examples.md b/docs/examples.md index 01d977a..9a7c19b 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -10,7 +10,7 @@ substrate = SubstrateInterface( keypair = Keypair.create_from_uri('//Alice') -balance_call = substrate.compose_call( +balance_call = await substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -19,7 +19,7 @@ balance_call = substrate.compose_call( } ) -call = substrate.compose_call( +call = await substrate.compose_call( call_module='Utility', call_function='batch', call_params={ @@ -27,7 +27,7 @@ call = substrate.compose_call( } ) -extrinsic = substrate.create_signed_extrinsic( +extrinsic = await substrate.create_signed_extrinsic( call=call, keypair=keypair, era={'period': 64} @@ -35,7 +35,7 @@ extrinsic = substrate.create_signed_extrinsic( try: - receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) + receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) print('Extrinsic "{}" included in block "{}"'.format( receipt.extrinsic_hash, receipt.block_hash @@ -44,7 +44,7 @@ try: if receipt.is_success: print('✅ Success, triggered events:') - for event in receipt.triggered_events: + for event in (await receipt.triggered_events()): print(f'* {event.value}') else: @@ -71,7 +71,7 @@ substrate = SubstrateInterface( keypair = Keypair.create_from_uri('//Alice') -call = substrate.compose_call( +call = await substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -95,7 +95,7 @@ substrate = SubstrateInterface( url="ws://127.0.0.1:9944" ) -result = substrate.query_map("System", "Account", max_results=100) +result = await substrate.query_map("System", "Account", max_results=100) for account, account_info in result: print(f'* {account.value}: {account_info.value}') @@ -122,7 +122,7 @@ multisig_account = substrate.generate_multisig_account( threshold=2 ) -call = substrate.compose_call( +call = await substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -132,18 +132,18 @@ call = substrate.compose_call( ) # Initiate multisig tx -extrinsic = substrate.create_multisig_extrinsic(call, keypair_alice, multisig_account, era={'period': 64}) +extrinsic = await substrate.create_multisig_extrinsic(call, keypair_alice, multisig_account, era={'period': 64}) -receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) +receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) if not receipt.is_success: print(f"⚠️ {receipt.error_message}") exit() # Finalize multisig tx with other signatory -extrinsic = substrate.create_multisig_extrinsic(call, keypair_bob, multisig_account, era={'period': 64}) +extrinsic = await substrate.create_multisig_extrinsic(call, keypair_bob, multisig_account, era={'period': 64}) -receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) +receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) if receipt.is_success: print(f"✅ {receipt.triggered_events}") @@ -167,14 +167,14 @@ keypair = Keypair.create_from_uri('//Alice') contract_address = "5GhwarrVMH8kjb8XyW6zCfURHbHy3v84afzLbADyYYX6H2Kk" # Check if contract is on chain -contract_info = substrate.query("Contracts", "ContractInfoOf", [contract_address]) +contract_info = await substrate.query("Contracts", "ContractInfoOf", [contract_address]) if contract_info.value: print(f'Found contract on chain: {contract_info.value}') # Create contract instance from deterministic address - contract = ContractInstance.create_from_address( + contract = await ContractInstance.create_from_address( contract_address=contract_address, metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper.json'), substrate=substrate @@ -182,7 +182,7 @@ if contract_info.value: else: # Upload WASM code - code = ContractCode.create_from_contract_files( + code = await ContractCode.create_from_contract_files( metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper.json'), wasm_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper.wasm'), substrate=substrate @@ -236,9 +236,9 @@ from substrateinterface import SubstrateInterface substrate = SubstrateInterface(url="ws://127.0.0.1:9944") block_number = 10 -block_hash = substrate.get_block_hash(block_number) +block_hash = await substrate.get_block_hash(block_number) -result = substrate.query( +result = await substrate.query( "System", "Account", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"], block_hash=block_hash ) @@ -261,10 +261,10 @@ from substrateinterface import SubstrateInterface substrate = SubstrateInterface(url="ws://127.0.0.1:9944") -def subscription_handler(obj, update_nr, subscription_id): +async def subscription_handler(obj, update_nr, subscription_id): print(f"New block #{obj['header']['number']}") - block = substrate.get_block(block_number=obj['header']['number']) + block = await substrate.get_block(block_number=obj['header']['number']) for idx, extrinsic in enumerate(block['extrinsics']): print(f'# {idx}: {extrinsic.value}') @@ -287,7 +287,7 @@ substrate = SubstrateInterface( ) -def subscription_handler(account_info_obj, update_nr, subscription_id): +async def subscription_handler(account_info_obj, update_nr, subscription_id): if update_nr == 0: print('Initial account data:', account_info_obj.value) @@ -301,7 +301,7 @@ def subscription_handler(account_info_obj, update_nr, subscription_id): return account_info_obj -result = substrate.query("System", "Account", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"], +result = await substrate.query("System", "Account", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"], subscription_handler=subscription_handler) print(result) @@ -313,7 +313,7 @@ print(result) from substrateinterface import SubstrateInterface -def subscription_handler(storage_key, updated_obj, update_nr, subscription_id): +async def subscription_handler(storage_key, updated_obj, update_nr, subscription_id): print(f"Update for {storage_key.params[0]}: {updated_obj.value}") @@ -321,10 +321,10 @@ substrate = SubstrateInterface(url="ws://127.0.0.1:9944") # Accounts to track storage_keys = [ - substrate.create_storage_key( + await substrate.create_storage_key( "System", "Account", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"] ), - substrate.create_storage_key( + await substrate.create_storage_key( "System", "Account", ["5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"] ) ] diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index f0da9c7..dab85e5 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -17,13 +17,13 @@ older or runtimes under development the `ss58_format` (default 42) and other pro ### Balance information of an account ```python -result = substrate.query('System', 'Account', ['F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T']) +result = await substrate.query('System', 'Account', ['F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T']) print(result.value['data']['free']) # 635278638077956496 ``` ### Create balance transfer extrinsic ```python -call = substrate.compose_call( +call = await substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -32,8 +32,8 @@ call = substrate.compose_call( } ) keypair = Keypair.create_from_uri('//Alice') -extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair) -receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) +extrinsic = await substrate.create_signed_extrinsic(call=call, keypair=keypair) +receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) print(f"Extrinsic '{receipt.extrinsic_hash}' sent and included in block '{receipt.block_hash}'") ``` diff --git a/docs/usage/call-runtime-apis.md b/docs/usage/call-runtime-apis.md index 1f4b7a4..f123d1a 100644 --- a/docs/usage/call-runtime-apis.md +++ b/docs/usage/call-runtime-apis.md @@ -8,14 +8,14 @@ A Runtime API facilitates this kind of communication between the outer node and ## Example ```python -result = substrate.runtime_call("AccountNonceApi", "account_nonce", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"]) +result = await substrate.runtime_call("AccountNonceApi", "account_nonce", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"]) # ``` ## List of available runtime APIs and methods ```python -runtime_calls = substrate.get_metadata_runtime_call_functions() +runtime_calls = await substrate.get_metadata_runtime_call_functions() #[ # # ... @@ -26,7 +26,7 @@ runtime_calls = substrate.get_metadata_runtime_call_functions() A helper function to compose the parameters for this runtime API call ```python -runtime_call = substrate.get_metadata_runtime_call_function("ContractsApi", "call") +runtime_call = await substrate.get_metadata_runtime_call_function("ContractsApi", "call") param_info = runtime_call.get_param_info() # ['AccountId', 'AccountId', 'u128', 'u64', (None, 'u128'), 'Bytes'] ``` diff --git a/docs/usage/cleanup-and-context-manager.md b/docs/usage/cleanup-and-context-manager.md index 98ebfd2..2685c37 100644 --- a/docs/usage/cleanup-and-context-manager.md +++ b/docs/usage/cleanup-and-context-manager.md @@ -7,7 +7,7 @@ When using the context manager this will be done automatically: ```python with SubstrateInterface(url="wss://rpc.polkadot.io") as substrate: - events = substrate.query("System", "Events") + events = await substrate.query("System", "Events") # connection is now closed ``` diff --git a/docs/usage/extrinsics.md b/docs/usage/extrinsics.md index a2d29a4..5ca09b2 100644 --- a/docs/usage/extrinsics.md +++ b/docs/usage/extrinsics.md @@ -11,7 +11,7 @@ See [the metadata documentation](https://polkascan.github.io/py-substrate-metada _Example:_ ```python -call = substrate.compose_call( +call = await substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -20,10 +20,10 @@ call = substrate.compose_call( } ) -extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair) +extrinsic = await substrate.create_signed_extrinsic(call=call, keypair=keypair) try: - receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) + receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) print(f"Extrinsic '{receipt.extrinsic_hash}' sent and included in block '{receipt.block_hash}'") except SubstrateRequestException as e: @@ -44,7 +44,7 @@ an extrinsic. Examples: ```python -receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) +receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) print(receipt.is_success) # False print(receipt.weight) # 216625000 print(receipt.total_fee_amount) # 2749998966 @@ -55,7 +55,7 @@ print(receipt.error_message['name']) # 'LiquidityRestrictions' ```python -receipt = substrate.retrieve_extrinsic_by_identifier("5233297-1") +receipt = await substrate.retrieve_extrinsic_by_identifier("5233297-1") print(receipt.is_success) # False print(receipt.extrinsic.call_module.name) # 'Identity' @@ -64,7 +64,7 @@ print(receipt.weight) # 359262000 print(receipt.total_fee_amount) # 2483332406 print(receipt.error_message['docs']) # [' Sender is not a sub-account.'] -for event in receipt.triggered_events: +for event in (await receipt.triggered_events()): print(f'* {event.value}') ``` @@ -92,7 +92,7 @@ multisig_account = substrate.generate_multisig_account( _Then initiate the multisig extrinsic by providing the call and a keypair of one of its signatories:_ ```python -call = substrate.compose_call( +call = await substrate.compose_call( call_module='System', call_function='remark_with_event', call_params={ @@ -100,8 +100,8 @@ call = substrate.compose_call( } ) -extrinsic = substrate.create_multisig_extrinsic(call, keypair_alice, multisig_account, era={'period': 64}) -receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) +extrinsic = await substrate.create_multisig_extrinsic(call, keypair_alice, multisig_account, era={'period': 64}) +receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) ``` _Then a second signatory approves and finalizes the call by providing the same call to another multisig extrinsic:_ @@ -119,8 +119,8 @@ multisig_account = substrate.generate_multisig_account( threshold=2 ) -extrinsic = substrate.create_multisig_extrinsic(call, keypair_charlie, multisig_account, era={'period': 64}) -receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) +extrinsic = await substrate.create_multisig_extrinsic(call, keypair_charlie, multisig_account, era={'period': 64}) +receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) ``` The call will be executed when the second and final multisig extrinsic is submitted, condition and state of the multig @@ -132,7 +132,7 @@ The structure of certain call parameters can be quite complex, then the `get_par can provide more insight how to construct those parameters: ```python -call_function = substrate.get_metadata_call_function("XTokens", "transfer") +call_function = await substrate.get_metadata_call_function("XTokens", "transfer") param_info = call_function.get_param_info() # { @@ -167,7 +167,7 @@ block. However, it is recommended to use specify an expiry window, so you know a extrinsic is not included in a block, it will be invalidated. ```python -extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair, era={'period': 64}) +extrinsic = await substrate.create_signed_extrinsic(call=call, keypair=keypair, era={'period': 64}) ``` The `period` specifies the number of blocks the extrinsic is valid counted from current head. diff --git a/docs/usage/ink-contract-interfacing.md b/docs/usage/ink-contract-interfacing.md index b3ae71f..ee996b5 100644 --- a/docs/usage/ink-contract-interfacing.md +++ b/docs/usage/ink-contract-interfacing.md @@ -19,7 +19,7 @@ substrate = SubstrateInterface( keypair = Keypair.create_from_uri('//Alice') # Deploy contract -code = ContractCode.create_from_contract_files( +code = await ContractCode.create_from_contract_files( metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper.json'), wasm_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper.wasm'), substrate=substrate @@ -41,7 +41,7 @@ print(f'✅ Deployed @ {contract.contract_address}') ```python # Create contract instance from deterministic address -contract = ContractInstance.create_from_address( +contract = await ContractInstance.create_from_address( contract_address=contract_address, metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper.json'), substrate=substrate diff --git a/docs/usage/keypair-creation-and-signing.md b/docs/usage/keypair-creation-and-signing.md index e29fbbb..d8398b6 100644 --- a/docs/usage/keypair-creation-and-signing.md +++ b/docs/usage/keypair-creation-and-signing.md @@ -81,7 +81,7 @@ substrate = SubstrateInterface( type_registry_preset='substrate-node-template', ) -call = substrate.compose_call( +call = await substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -108,7 +108,7 @@ signature = keypair.sign(signature_payload) ```python keypair = Keypair(ss58_address="5EChUec3ZQhUvY1g52ZbfBVkqjUY9Kcr6mcEvQMbmd38shQL") -extrinsic = substrate.create_signed_extrinsic( +extrinsic = await substrate.create_signed_extrinsic( call=call, keypair=keypair, era=era, @@ -116,7 +116,7 @@ extrinsic = substrate.create_signed_extrinsic( signature=signature ) -result = substrate.submit_extrinsic( +result = await substrate.submit_extrinsic( extrinsic=extrinsic ) diff --git a/docs/usage/query-storage.md b/docs/usage/query-storage.md index 807e579..4c4e1ef 100644 --- a/docs/usage/query-storage.md +++ b/docs/usage/query-storage.md @@ -9,7 +9,7 @@ See the [metadata documentation](https://polkascan.github.io/py-substrate-metada ## Example ```python -result = substrate.query('System', 'Account', ['F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T']) +result = await substrate.query('System', 'Account', ['F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T']) print(result.value['nonce']) # 7695 print(result.value['data']['free']) # 635278638077956496 @@ -18,7 +18,7 @@ print(result.value['data']['free']) # 635278638077956496 ## State at a specific block hash ```python -account_info = substrate.query( +account_info = await substrate.query( module='System', storage_function='Account', params=['F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T'], @@ -36,7 +36,7 @@ Some storage functions need parameters and some of those parameter types can be To retrieve more information how to format those storage function parameters, the helper function `get_param_info()` is available: ```python -storage_function = substrate.get_metadata_storage_function("Tokens", "TotalIssuance") +storage_function = await substrate.get_metadata_storage_function("Tokens", "TotalIssuance") print(storage_function.get_param_info()) # [{ @@ -56,18 +56,18 @@ This will batch all the requested storage entries in one RPC request. ```python storage_keys = [ - substrate.create_storage_key( + await substrate.create_storage_key( "System", "Account", ["F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T"] ), - substrate.create_storage_key( + await substrate.create_storage_key( "System", "Account", ["GSEX8kR4Kz5UZGhvRUCJG93D5hhTAoVZ5tAe6Zne7V42DSi"] ), - substrate.create_storage_key( + await substrate.create_storage_key( "Staking", "Bonded", ["GSEX8kR4Kz5UZGhvRUCJG93D5hhTAoVZ5tAe6Zne7V42DSi"] ) ] -result = substrate.query_multi(storage_keys) +result = await substrate.query_multi(storage_keys) for storage_key, value_obj in result: print(storage_key, value_obj) @@ -81,7 +81,7 @@ The result is a `QueryMapResult` object, which is an iterator: ```python # Retrieve the first 199 System.Account entries -result = substrate.query_map('System', 'Account', max_results=199) +result = await substrate.query_map('System', 'Account', max_results=199) for account, account_info in result: print(f"Free balance of account '{account.value}': {account_info.value['data']['free']}") @@ -92,7 +92,7 @@ maximum `page_size` restricted by the RPC node is 1000 ```python # Retrieve all System.Account entries in batches of 200 (automatically appended by `QueryMapResult` iterator) -result = substrate.query_map('System', 'Account', page_size=200, max_results=400) +result = await substrate.query_map('System', 'Account', page_size=200, max_results=400) for account, account_info in result: print(f"Free balance of account '{account.value}': {account_info.value['data']['free']}") @@ -101,7 +101,7 @@ for account, account_info in result: Querying a `DoubleMap` storage function: ```python -era_stakers = substrate.query_map( +era_stakers = await substrate.query_map( module='Staking', storage_function='ErasStakers', params=[2100] diff --git a/docs/usage/subscriptions.md b/docs/usage/subscriptions.md index 5140008..549c875 100644 --- a/docs/usage/subscriptions.md +++ b/docs/usage/subscriptions.md @@ -11,7 +11,7 @@ is returned. This value will be returned as a result of the query and finally au updates. ```python -def subscription_handler(account_info_obj, update_nr, subscription_id): +async def subscription_handler(account_info_obj, update_nr, subscription_id): if update_nr == 0: print('Initial account data:', account_info_obj.value) @@ -25,7 +25,7 @@ def subscription_handler(account_info_obj, update_nr, subscription_id): return account_info_obj -result = substrate.query("System", "Account", ["5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY"], +result = await substrate.query("System", "Account", ["5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY"], subscription_handler=subscription_handler) print(result) @@ -41,15 +41,15 @@ a final value is returned. This value will be returned as a result of subscripti unsubscribed from further updates. ```python -def subscription_handler(storage_key, updated_obj, update_nr, subscription_id): +async def subscription_handler(storage_key, updated_obj, update_nr, subscription_id): print(f"Update for {storage_key.params[0]}: {updated_obj.value}") # Accounts to track storage_keys = [ - substrate.create_storage_key( + await substrate.create_storage_key( "System", "Account", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"] ), - substrate.create_storage_key( + await substrate.create_storage_key( "System", "Account", ["5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"] ) ] @@ -62,10 +62,10 @@ result = substrate.subscribe_storage( ## Subscribe to new block headers ```python -def subscription_handler(obj, update_nr, subscription_id): +async def subscription_handler(obj, update_nr, subscription_id): print(f"New block #{obj['header']['number']}") - block = substrate.get_block(block_number=obj['header']['number']) + block = await substrate.get_block(block_number=obj['header']['number']) for idx, extrinsic in enumerate(block['extrinsics']): print(f'# {idx}: {extrinsic.value}') diff --git a/examples/balance_transfer.py b/examples/balance_transfer.py index 821520e..db0ffdd 100644 --- a/examples/balance_transfer.py +++ b/examples/balance_transfer.py @@ -14,55 +14,60 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio from substrateinterface import SubstrateInterface, Keypair from substrateinterface.exceptions import SubstrateRequestException # import logging # logging.basicConfig(level=logging.DEBUG) -substrate = SubstrateInterface( - url="ws://127.0.0.1:9944" -) +async def main(): + substrate = SubstrateInterface( + url="ws://127.0.0.1:9944" + ) -substrate = SubstrateInterface(url="ws://127.0.0.1:9944") -keypair_alice = Keypair.create_from_uri('//Alice', ss58_format=substrate.ss58_format) -print(keypair_alice.ss58_address) + substrate = SubstrateInterface(url="ws://127.0.0.1:9944") + keypair_alice = Keypair.create_from_uri('//Alice', ss58_format=substrate.ss58_format) + print(keypair_alice.ss58_address) -keypair = Keypair.create_from_uri('//Alice') + keypair = Keypair.create_from_uri('//Alice') -call = substrate.compose_call( - call_module='Balances', - call_function='transfer_keep_alive', - call_params={ - 'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', - 'value': 1 * 10**15 - } -) + call = await substrate.compose_call( + call_module='Balances', + call_function='transfer_keep_alive', + call_params={ + 'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', + 'value': 1 * 10**15 + } + ) -print(call.data.to_hex()) + print(call.data.to_hex()) -extrinsic = substrate.create_signed_extrinsic( - call=call, - keypair=keypair, - era={'period': 64} -) + extrinsic = await substrate.create_signed_extrinsic( + call=call, + keypair=keypair, + era={'period': 64} + ) -try: - receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) + try: + receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) - print('Extrinsic "{}" included in block "{}"'.format( - receipt.extrinsic_hash, receipt.block_hash - )) + print('Extrinsic "{}" included in block "{}"'.format( + receipt.extrinsic_hash, receipt.block_hash + )) - if receipt.is_success: + if receipt.is_success: - print('✅ Success, triggered events:') - for event in receipt.triggered_events: - print(f'* {event.value}') + print('✅ Success, triggered events:') + for event in (await receipt.triggered_events()): + print(f'* {event.value}') - else: - print('⚠️ Extrinsic Failed: ', receipt.error_message) + else: + print('⚠️ Extrinsic Failed: ', receipt.error_message) -except SubstrateRequestException as e: - print("Failed to send: {}".format(e)) + except SubstrateRequestException as e: + print("Failed to send: {}".format(e)) + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/examples/batch_call.py b/examples/batch_call.py index 1992f11..1c79e46 100644 --- a/examples/batch_call.py +++ b/examples/batch_call.py @@ -14,57 +14,63 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio from substrateinterface import SubstrateInterface, Keypair from substrateinterface.exceptions import SubstrateRequestException # import logging # logging.basicConfig(level=logging.DEBUG) -substrate = SubstrateInterface( - url="ws://127.0.0.1:9944" -) +async def main(): -keypair = Keypair.create_from_uri('//Alice') + substrate = SubstrateInterface( + url="ws://127.0.0.1:9944" + ) -balance_call = substrate.compose_call( - call_module='Balances', - call_function='transfer_keep_alive', - call_params={ - 'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', - 'value': 1 * 10**15 - } -) + keypair = Keypair.create_from_uri('//Alice') -call = substrate.compose_call( - call_module='Utility', - call_function='batch', - call_params={ - 'calls': [balance_call, balance_call] - } -) + balance_call = await substrate.compose_call( + call_module='Balances', + call_function='transfer_keep_alive', + call_params={ + 'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', + 'value': 1 * 10**15 + } + ) -extrinsic = substrate.create_signed_extrinsic( - call=call, - keypair=keypair, - era={'period': 64} -) + call = await substrate.compose_call( + call_module='Utility', + call_function='batch', + call_params={ + 'calls': [balance_call, balance_call] + } + ) -try: - receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) + extrinsic = await substrate.create_signed_extrinsic( + call=call, + keypair=keypair, + era={'period': 64} + ) - print('Extrinsic "{}" included in block "{}"'.format( - receipt.extrinsic_hash, receipt.block_hash - )) + try: + receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) - if receipt.is_success: + print('Extrinsic "{}" included in block "{}"'.format( + receipt.extrinsic_hash, receipt.block_hash + )) - print('✅ Success, triggered events:') - for event in receipt.triggered_events: - print(f'* {event.value}') + if receipt.is_success: - else: - print('⚠️ Extrinsic Failed: ', receipt.error_message) + print('✅ Success, triggered events:') + for event in (await receipt.triggered_events()): + print(f'* {event.value}') + else: + print('⚠️ Extrinsic Failed: ', receipt.error_message) -except SubstrateRequestException as e: - print("Failed to send: {}".format(e)) + + except SubstrateRequestException as e: + print("Failed to send: {}".format(e)) + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/examples/create_and_exec_contract.py b/examples/create_and_exec_contract.py index 6edc837..6b8d3db 100644 --- a/examples/create_and_exec_contract.py +++ b/examples/create_and_exec_contract.py @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio import os from substrateinterface.contracts import ContractCode, ContractInstance @@ -23,66 +24,70 @@ import logging logging.basicConfig(level=logging.DEBUG) -substrate = SubstrateInterface(url='wss://rococo-contracts-rpc.polkadot.io') -keypair = Keypair.create_from_uri('//Alice') -contract_address = "5DYXHYiH5jPj8orDw5HSFJhmATe8NtmbguG3vs53v8RgSHTW" +async def main(): + substrate = SubstrateInterface(url='wss://rococo-contracts-rpc.polkadot.io') + keypair = Keypair.create_from_uri('//Alice') + contract_address = "5DYXHYiH5jPj8orDw5HSFJhmATe8NtmbguG3vs53v8RgSHTW" -# Check if contract is on chain -contract_info = substrate.query("Contracts", "ContractInfoOf", [contract_address]) + # Check if contract is on chain + contract_info = await substrate.query("Contracts", "ContractInfoOf", [contract_address]) -if contract_info.value: + if contract_info.value: - print(f'Found contract on chain: {contract_info.value}') + print(f'Found contract on chain: {contract_info.value}') - # Create contract instance from deterministic address - contract = ContractInstance.create_from_address( - contract_address=contract_address, - metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v5.json'), - substrate=substrate - ) -else: + # Create contract instance from deterministic address + contract = await ContractInstance.create_from_address( + contract_address=contract_address, + metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v5.json'), + substrate=substrate + ) + else: - # Upload WASM code - code = ContractCode.create_from_contract_files( - metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v5.json'), - wasm_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v5.wasm'), - substrate=substrate - ) + # Upload WASM code + code = await ContractCode.create_from_contract_files( + metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v5.json'), + wasm_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v5.wasm'), + substrate=substrate + ) - # Deploy contract - print('Deploy contract...') - contract = code.deploy( - keypair=keypair, - constructor="new", - args={'init_value': True}, - value=0, - gas_limit={'ref_time': 147523041, 'proof_size': 16689}, - upload_code=True - ) + # Deploy contract + print('Deploy contract...') + contract = await code.deploy( + keypair=keypair, + constructor="new", + args={'init_value': True}, + value=0, + gas_limit={'ref_time': 147523041, 'proof_size': 16689}, + upload_code=True + ) - print(f'✅ Deployed @ {contract.contract_address}') + print(f'✅ Deployed @ {contract.contract_address}') -# Read current value -result = contract.read(keypair, 'get') -print('Current value of "get":', result.contract_result_data) + # Read current value + result = await contract.read(keypair, 'get') + print('Current value of "get":', result.contract_result_data) -# Do a gas estimation of the message -gas_predit_result = contract.read(keypair, 'flip') + # Do a gas estimation of the message + gas_predit_result = await contract.read(keypair, 'flip') -print('Result of dry-run: ', gas_predit_result.value) -print('Gas estimate: ', gas_predit_result.gas_required) + print('Result of dry-run: ', gas_predit_result.value) + print('Gas estimate: ', gas_predit_result.gas_required) -# Do the actual call -print('Executing contract call...') -contract_receipt = contract.exec(keypair, 'flip', args={ + # Do the actual call + print('Executing contract call...') + contract_receipt = await contract.exec(keypair, 'flip', args={ -}, gas_limit=gas_predit_result.gas_required) + }, gas_limit=gas_predit_result.gas_required) -if contract_receipt.is_success: - print(f'Events triggered in contract: {contract_receipt.contract_events}') -else: - print(f'Error message: {contract_receipt.error_message}') + if contract_receipt.is_success: + print(f'Events triggered in contract: {contract_receipt.contract_events}') + else: + print(f'Error message: {contract_receipt.error_message}') -result = contract.read(keypair, 'get') + result = contract.read(keypair, 'get') -print('Current value of "get":', result.contract_result_data) + print('Current value of "get":', result.contract_result_data) + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/examples/extensions.py b/examples/extensions.py index 8a7f83d..b71d3b0 100644 --- a/examples/extensions.py +++ b/examples/extensions.py @@ -1,4 +1,5 @@ -from datetime import datetime, timedelta +import asyncio +from datetime import datetime from substrateinterface import SubstrateInterface from substrateinterface.extensions import SubstrateNodeExtension @@ -6,22 +7,27 @@ import logging logging.basicConfig(level=logging.DEBUG) -substrate = SubstrateInterface(url="wss://rpc.polkadot.io") +async def main(): -substrate.register_extension(SubstrateNodeExtension(max_block_range=100)) + substrate = SubstrateInterface(url="wss://rpc.polkadot.io") -# Search for block number corresponding a specific datetime -block_datetime = datetime(2022, 1, 1, 0, 0, 0) -block_number = substrate.extensions.search_block_number(block_datetime=block_datetime) -print(f'Block number for {block_datetime}: #{block_number}') + substrate.register_extension(SubstrateNodeExtension(max_block_range=100)) -# account_info = substrate.runtime. -# exit() + # Search for block number corresponding a specific datetime + block_datetime = datetime(2022, 1, 1, 0, 0, 0) + block_number = substrate.extensions.search_block_number(block_datetime=block_datetime) + print(f'Block number for {block_datetime}: #{block_number}') -# Returns all `Balances.Transfer` events from the last 30 blocks -events = substrate.extensions.filter_events(pallet_name="Balances", event_name="Transfer", block_start=-30) -print(events) + # account_info = substrate.runtime. + # exit() -# All Timestamp extrinsics in block range #3 until #6 -extrinsics = substrate.extensions.filter_extrinsics(pallet_name="Timestamp", block_start=3, block_end=6) -print(extrinsics) + # Returns all `Balances.Transfer` events from the last 30 blocks + events = substrate.extensions.filter_events(pallet_name="Balances", event_name="Transfer", block_start=-30) + print(events) + + # All Timestamp extrinsics in block range #3 until #6 + extrinsics = substrate.extensions.filter_extrinsics(pallet_name="Timestamp", block_start=3, block_end=6) + print(extrinsics) + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/examples/fee_info.py b/examples/fee_info.py index 4f20681..6416791 100644 --- a/examples/fee_info.py +++ b/examples/fee_info.py @@ -14,29 +14,33 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio from substrateinterface import SubstrateInterface, Keypair # import logging # logging.basicConfig(level=logging.DEBUG) +async def main(): + substrate = SubstrateInterface( + url="ws://127.0.0.1:9944" + ) -substrate = SubstrateInterface( - url="ws://127.0.0.1:9944" -) + keypair = Keypair.create_from_uri('//Alice') -keypair = Keypair.create_from_uri('//Alice') + call = await substrate.compose_call( + call_module='Balances', + call_function='transfer_keep_alive', + call_params={ + 'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', + 'value': 1 * 10**15 + } + ) -call = substrate.compose_call( - call_module='Balances', - call_function='transfer_keep_alive', - call_params={ - 'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', - 'value': 1 * 10**15 - } -) + # Get payment info + payment_info = substrate.get_payment_info(call=call, keypair=keypair) -# Get payment info -payment_info = substrate.get_payment_info(call=call, keypair=keypair) + print("Payment info: ", payment_info) -print("Payment info: ", payment_info) +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/examples/historic_balance.py b/examples/historic_balance.py index d5c10e8..0829132 100644 --- a/examples/historic_balance.py +++ b/examples/historic_balance.py @@ -14,27 +14,32 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio from substrateinterface import SubstrateInterface # # Enable for debugging purposes # import logging # logging.basicConfig(level=logging.DEBUG) -substrate = SubstrateInterface(url="ws://127.0.0.1:9944") +async def main(): + substrate = SubstrateInterface(url="ws://127.0.0.1:9944") -block_number = 10 -block_hash = substrate.get_block_hash(block_number) + block_number = 10 + block_hash = await substrate.get_block_hash(block_number) -result = substrate.query( - "System", "Account", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"], block_hash=block_hash -) + result = await substrate.query( + "System", "Account", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"], block_hash=block_hash + ) -def format_balance(amount: int): - amount = format(amount / 10**substrate.properties.get('tokenDecimals', 0), ".15g") - return f"{amount} {substrate.properties.get('tokenSymbol', 'UNIT')}" + def format_balance(amount: int): + amount = format(amount / 10**substrate.properties.get('tokenDecimals', 0), ".15g") # type: ignore[assignment] + return f"{amount} {substrate.properties.get('tokenSymbol', 'UNIT')}" -balance = (result.value["data"]["free"] + result.value["data"]["reserved"]) + balance = (result.value["data"]["free"] + result.value["data"]["reserved"]) -print(f"Balance @ {block_number}: {format_balance(balance)}") + print(f"Balance @ {block_number}: {format_balance(balance)}") + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/multisig.py b/examples/multisig.py index 52b1e27..beb722d 100644 --- a/examples/multisig.py +++ b/examples/multisig.py @@ -14,55 +14,59 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio from substrateinterface import SubstrateInterface, Keypair import logging logging.basicConfig(level=logging.DEBUG) -substrate = SubstrateInterface(url="ws://127.0.0.1:9944") +async def main(): + substrate = SubstrateInterface(url="ws://127.0.0.1:9944") -keypair_alice = Keypair.create_from_uri('//Alice', ss58_format=substrate.ss58_format) -keypair_bob = Keypair.create_from_uri('//Bob', ss58_format=substrate.ss58_format) -keypair_charlie = Keypair.create_from_uri('//Charlie', ss58_format=substrate.ss58_format) + keypair_alice = Keypair.create_from_uri('//Alice', ss58_format=substrate.ss58_format) + keypair_bob = Keypair.create_from_uri('//Bob', ss58_format=substrate.ss58_format) + keypair_charlie = Keypair.create_from_uri('//Charlie', ss58_format=substrate.ss58_format) -# Generate multi-sig account from signatories and threshold -multisig_account = substrate.generate_multisig_account( - signatories=[ - keypair_alice.ss58_address, - keypair_bob.ss58_address, - keypair_charlie.ss58_address - ], - threshold=2 -) + # Generate multi-sig account from signatories and threshold + multisig_account = substrate.generate_multisig_account( + signatories=[ + keypair_alice.ss58_address, + keypair_bob.ss58_address, + keypair_charlie.ss58_address + ], + threshold=2 + ) -call = substrate.compose_call( - call_module='Balances', - call_function='transfer_keep_alive', - call_params={ - 'dest': keypair_alice.ss58_address, - 'value': 3 * 10 ** 3 - } -) + call = await substrate.compose_call( + call_module='Balances', + call_function='transfer_keep_alive', + call_params={ + 'dest': keypair_alice.ss58_address, + 'value': 3 * 10 ** 3 + } + ) -# Initiate multisig tx -extrinsic = substrate.create_multisig_extrinsic(call, keypair_alice, multisig_account, era={'period': 64}) + # Initiate multisig tx + extrinsic = await substrate.create_multisig_extrinsic(call, keypair_alice, multisig_account, era={'period': 64}) -receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) + receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) -if not receipt.is_success: - print(f"⚠️ {receipt.error_message}") - exit() + if not receipt.is_success: + print(f"⚠️ {receipt.error_message}") + exit() -# Finalize multisig tx with other signatory -extrinsic = substrate.create_multisig_extrinsic(call, keypair_bob, multisig_account, era={'period': 64}) + # Finalize multisig tx with other signatory + extrinsic = await substrate.create_multisig_extrinsic(call, keypair_bob, multisig_account, era={'period': 64}) -receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) + receipt = await substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) -if receipt.is_success: - print(f"✅ {receipt.triggered_events}") -else: - print(f"⚠️ {receipt.error_message}") + if receipt.is_success: + print(f"✅ {receipt.triggered_events}") + else: + print(f"⚠️ {receipt.error_message}") +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/examples/storage_subscription.py b/examples/storage_subscription.py index 51badaa..28c2df0 100644 --- a/examples/storage_subscription.py +++ b/examples/storage_subscription.py @@ -13,28 +13,33 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import asyncio from substrateinterface import SubstrateInterface -def subscription_handler(storage_key, updated_obj, update_nr, subscription_id): +async def subscription_handler(storage_key, updated_obj, update_nr, subscription_id): print(f"Update for {storage_key}: {updated_obj.value}") -substrate = SubstrateInterface(url="ws://127.0.0.1:9944") +async def main(): + substrate = SubstrateInterface(url="ws://127.0.0.1:9944") -# Accounts to track -storage_keys = [ - substrate.create_storage_key( - "System", "Account", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"] - ), - substrate.create_storage_key( - "System", "Account", ["5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"] - ), - substrate.create_storage_key( - "System", "Events" - ), -] + # Accounts to track + storage_keys = [ + await substrate.create_storage_key( + "System", "Account", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"] + ), + await substrate.create_storage_key( + "System", "Account", ["5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"] + ), + await substrate.create_storage_key( + "System", "Events" + ), + ] -result = substrate.subscribe_storage( - storage_keys=storage_keys, subscription_handler=subscription_handler -) + substrate.subscribe_storage( + storage_keys=storage_keys, subscription_handler=subscription_handler + ) + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..428e6a0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,94 @@ +[project] +name = "substrate-interface-async" +version = "1.7.10" +description = "Library for interfacing with a Substrate node (async fork)" + +authors = [ + { name = "Stichting Polkascan (Polkascan Foundation)", email = "info@polkascan.org" } +] +maintainers = [ + { name = "Lev Gorodetskii", email = "github@drsr.io" } +] +classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', +] +keywords = ["interface", "polkascan", "polkadot", "substrate", "blockchain", "rpc", "kusama"] +readme = "README.md" +requires-python = ">=3.9,<4" + +dependencies = [ + "aiohttp>=3.11.6", + "scalecodec>=1.2.11", + "xxhash>=3.5.0", + "websocket-client>=1.8.0", + "orjson>=3.10.12", +] + +[project.optional-dependencies] +full = [ + "base58>=2.1.1", + "certifi>=2024.8.30", + "ecdsa>=0.19.0", + "eth-keys>=0.6.0", + "eth-utils>=5.1.0", + "idna>=3.10", + "py-bip39-bindings>=0.1.12", + "py-ed25519-zebra-bindings>=1.1.0", + "py-sr25519-bindings>=0.2.1", + "pycryptodome>=3.21.0", + "pynacl>=1.5.0", +] + +[project.urls] +"Homepage" = "https://github.com/dipdup-io/py-substrate-interface-async" + +[dependency-groups] +dev = [ + "black>=24.10.0", + "mkdocs>=1.6.1", + "mkdocs-autorefs>=1.2.0", + "mkdocs-material>=9.5.45", + "mkdocstrings[python]>=0.27.0", + "mypy>=1.13.0", + "pytest-asyncio>=0.24.0", + "pytest>=8.3.3", + "ruff>=0.7.4", + "pytest-coverage>=0.0", +] + +# [tool.black] +# line-length = 120 +# target-version = ["py312"] +# skip-string-normalization = true + +# [tool.ruff] +# line-length = 120 +# target-version = "py312" + +# [tool.ruff.lint] +# # ignore = [ +# # "E402", # module level import not at top of file +# # "E501", # line too long +# # ] +# # extend-select = ["B", "C4", "FA", "G", "I", "PTH", "Q", "RET", "RUF", "TCH", "UP"] +# extend-select = ["I", "Q"] +# flake8-quotes = { inline-quotes = "single", multiline-quotes = "double" } +# isort = { force-single-line = true, known-first-party = ["substrateinterface"] } + +# [tool.mypy] +# python_version = "3.12" +# strict = false + +[tool.pytest.ini_options] +addopts="--cov-report=term-missing --cov=substrateinterface --cov-report=xml -s -v" +asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "function" +log_cli_level = "WARNING" +testpaths = ["test"] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index ba6d35a..0000000 --- a/requirements.txt +++ /dev/null @@ -1,23 +0,0 @@ -websocket-client>=0.57.0,<2 -base58>=1.0.3,<3 -certifi>=2019.3.9 -idna>=2.1.0,<4 -requests>=2.21.0,<3 -xxhash>=1.3.0,<4 -pytest>=4.4.0 -ecdsa>=0.17.0,<1 -eth-keys>=0.2.1,<1 -eth_utils>=1.3.0,<6 -pycryptodome>=3.11.0,<4 -PyNaCl>=1.0.1,<2 - -scalecodec>=1.2.10,<1.3 -py-sr25519-bindings>=0.2.0,<1 -py-ed25519-zebra-bindings>=1.0,<2 -py-bip39-bindings>=0.1.9,<1 - -mkdocs -mkdocs-material -mkdocs-autorefs -mkdocstrings -mkdocstrings[python] diff --git a/setup.py b/setup.py deleted file mode 100644 index 4b2eef9..0000000 --- a/setup.py +++ /dev/null @@ -1,256 +0,0 @@ -# Python Substrate Interface Library -# -# Copyright 2018-2020 Stichting Polkascan (Polkascan Foundation). -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A setuptools based setup module. - -See: -https://packaging.python.org/guides/distributing-packages-using-setuptools/ -https://github.com/pypa/sampleproject -""" - -# Always prefer setuptools over distutils -from setuptools import setup, find_packages -from os import path, environ -# io.open is needed for projects that support Python 2.7 -# It ensures open() defaults to text mode with universal newlines, -# and accepts an argument to specify the text encoding -# Python 3 only projects can skip this import -from io import open - -if environ.get('TRAVIS_TAG'): - version = environ['TRAVIS_TAG'].replace('v', '') -elif environ.get('CI_COMMIT_TAG'): - version = environ['CI_COMMIT_TAG'].replace('v', '') -elif environ.get('GITHUB_REF'): - - if not environ['GITHUB_REF'].startswith('refs/tags/v'): - raise ValueError('Incorrect tag format {}'.format(environ['GITHUB_REF'])) - - version = environ['GITHUB_REF'].replace('refs/tags/v', '') -else: - raise ValueError('Missing commit tag, can\'t set version') - -here = path.abspath(path.dirname(__file__)) - -# Get the long description from the README file -with open(path.join(here, 'README.md'), encoding='utf-8') as f: - long_description = f.read() - -# Arguments marked as "Required" below must be included for upload to PyPI. -# Fields marked as "Optional" may be commented out. - -setup( - # This is the name of your project. The first time you publish this - # package, this name will be registered for you. It will determine how - # users can install this project, e.g.: - # - # $ pip install sampleproject - # - # And where it will live on PyPI: https://pypi.org/project/sampleproject/ - # - # There are some restrictions on what makes a valid project name - # specification here: - # https://packaging.python.org/specifications/core-metadata/#name - name='substrate-interface', # Required - - # Versions should comply with PEP 440: - # https://www.python.org/dev/peps/pep-0440/ - # - # For a discussion on single-sourcing the version across setup.py and the - # project code, see - # https://packaging.python.org/en/latest/single_source_version.html - version=version, # Required - - # This is a one-line description or tagline of what your project does. This - # corresponds to the "Summary" metadata field: - # https://packaging.python.org/specifications/core-metadata/#summary - description='Library for interfacing with a Substrate node', # Optional - - # This is an optional longer description of your project that represents - # the body of text which users will see when they visit PyPI. - # - # Often, this is the same as your README, so you can just read it in from - # that file directly (as we have already done above) - # - # This field corresponds to the "Description" metadata field: - # https://packaging.python.org/specifications/core-metadata/#description-optional - long_description=long_description, # Optional - - # Denotes that our long_description is in Markdown; valid values are - # text/plain, text/x-rst, and text/markdown - # - # Optional if long_description is written in reStructuredText (rst) but - # required for plain-text or Markdown; if unspecified, "applications should - # attempt to render [the long_description] as text/x-rst; charset=UTF-8 and - # fall back to text/plain if it is not valid rst" (see link below) - # - # This field corresponds to the "Description-Content-Type" metadata field: - # https://packaging.python.org/specifications/core-metadata/#description-content-type-optional - long_description_content_type='text/markdown', # Optional (see note above) - - # This should be a valid link to your project's main homepage. - # - # This field corresponds to the "Home-Page" metadata field: - # https://packaging.python.org/specifications/core-metadata/#home-page-optional - url='https://github.com/polkascan/py-substrate-interface', # Optional - - # This should be your name or the name of the organization which owns the - # project. - author='Stichting Polkascan (Polkascan Foundation)', # Optional - - # This should be a valid email address corresponding to the author listed - # above. - author_email='info@polkascan.org', # Optional - - # Classifiers help users find your project by categorizing it. - # - # For a list of valid classifiers, see https://pypi.org/classifiers/ - classifiers=[ # Optional - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable - 'Development Status :: 5 - Production/Stable', - - # Indicate who your project is intended for - 'Intended Audience :: Developers', - - # Pick your license as you wish - 'License :: OSI Approved :: Apache Software License', - - # Specify the Python versions you support here. In particular, ensure - # that you indicate whether you support Python 2, Python 3 or both. - # These classifiers are *not* checked by 'pip install'. See instead - # 'python_requires' below. - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - ], - - # This field adds keywords for your project which will appear on the - # project page. What does your project relate to? - # - # Note that this is a string of words separated by whitespace, not a list. - keywords='interface polkascan polkadot substrate blockchain rpc kusama', # Optional - - # You can just specify package directories manually here if your project is - # simple. Or you can use find_packages(). - # - # Alternatively, if you just want to distribute a single Python file, use - # the `py_modules` argument instead as follows, which will expect a file - # called `my_module.py` to exist: - # - # py_modules=["my_module"], - # - #packages=find_packages(exclude=['contrib', 'docs', 'tests', 'test']), # Required - packages=find_packages(exclude=['contrib', 'docs', 'tests', 'test']), # Required - - # Specify which Python versions you support. In contrast to the - # 'Programming Language' classifiers above, 'pip install' will check this - # and refuse to install the project if the version does not match. If you - # do not support Python 2, you can simplify this to '>=3.5' or similar, see - # https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires - - #python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4', - python_requires='>=3.7, <4', - - # This field lists other packages that your project depends on to run. - # Any package you put here will be installed by pip when your project is - # installed, so they must be valid existing projects. - # - # For an analysis of "install_requires" vs pip's requirements files see: - # https://packaging.python.org/en/latest/requirements.html - install_requires=[ - 'websocket-client>=0.57.0,<2', - 'base58>=1.0.3,<3', - 'certifi>=2019.3.9', - 'idna>=2.1.0,<4', - 'requests>=2.21.0,<3', - 'xxhash>=1.3.0,<4', - 'ecdsa>=0.17.0,<1', - 'eth-keys>=0.2.1,<1', - 'eth_utils>=1.3.0,<6', - 'pycryptodome>=3.11.0,<4', - 'PyNaCl>=1.0.1,<2', - 'scalecodec>=1.2.10,<1.3', - 'py-sr25519-bindings>=0.2.0,<1', - 'py-ed25519-zebra-bindings>=1.0,<2', - 'py-bip39-bindings>=0.1.9,<1' - ], - - # List additional groups of dependencies here (e.g. development - # dependencies). Users will be able to install these using the "extras" - # syntax, for example: - # - # $ pip install sampleproject[dev] - # - # Similar to `install_requires` above, these must be valid existing - # projects. - extras_require={ # Optional - #'dev': ['check-manifest'], - 'test': ['coverage', 'pytest'], - }, - - # If there are data files included in your packages that need to be - # installed, specify them here. - # - # If using Python 2.6 or earlier, then these have to be included in - # MANIFEST.in as well. - - # package_data={ # Optional - # 'sample': ['package_data.dat'], - # }, - - # Although 'package_data' is the preferred approach, in some case you may - # need to place data files outside of your packages. See: - # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files - # - # In this case, 'data_file' will be installed into '/my_data' - # data_files=[('my_data', ['data/data_file'])], # Optional - - # To provide executable scripts, use entry points in preference to the - # "scripts" keyword. Entry points provide cross-platform support and allow - # `pip` to create the appropriate form of executable for the target - # platform. - # - # For example, the following would provide a command called `sample` which - # executes the function `main` from this package when invoked: - - # entry_points={ # Optional - # 'console_scripts': [ - # 'sample=sample:main', - # ], - # }, - - # List additional URLs that are relevant to your project as a dict. - # - # This field corresponds to the "Project-URL" metadata fields: - # https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use - # - # Examples listed include a pattern for specifying where the package tracks - # issues, where the source is hosted, where to say thanks to the package - # maintainers, and where to support the project financially. The key is - # what's used to render the link text on PyPI. - # project_urls={ # Optional - # 'Bug Reports': 'https://github.com/pypa/sampleproject/issues', - # 'Funding': 'https://donate.pypi.org', - # 'Say Thanks!': 'http://saythanks.io/to/example', - # 'Source': 'https://github.com/pypa/sampleproject/', - # }, -) diff --git a/substrateinterface/__init__.py b/substrateinterface/__init__.py index 9d8717e..28a5725 100644 --- a/substrateinterface/__init__.py +++ b/substrateinterface/__init__.py @@ -14,10 +14,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .base import * -from .contracts import * -from .keypair import * -from .interfaces import * -from .extensions import * - -__all__ = (base.__all__ + contracts.__all__ + keypair.__all__ + interfaces.__all__ + extensions.__all__) +from .base import * # noqa: F403 +from .contracts import * # noqa: F403 +from .contracts import * # noqa: F403 +from .exceptions import * # noqa: F403 +from .interfaces import * # noqa: F403 +from .key import * # noqa: F403 +from .keypair import * # noqa: F403 +from .storage import * # noqa: F403 diff --git a/substrateinterface/base.py b/substrateinterface/base.py index ae4d497..801325f 100644 --- a/substrateinterface/base.py +++ b/substrateinterface/base.py @@ -15,23 +15,27 @@ # limitations under the License. +from collections.abc import AsyncIterator +from functools import cached_property import warnings from datetime import datetime from hashlib import blake2b -import json +import orjson import logging -import requests -from typing import Optional, Union, List +from aiohttp import ClientSession +from typing import Any, Awaitable, Callable, Optional, Union, List from websocket import create_connection, WebSocketConnectionClosedException -from scalecodec.base import ScaleBytes, RuntimeConfigurationObject, ScaleType -from scalecodec.types import GenericCall, GenericExtrinsic, Extrinsic, MultiAccountId, GenericRuntimeCallDefinition -from scalecodec.type_registry import load_type_registry_preset -from scalecodec.updater import update_type_registries +from scalecodec.base import ScaleBytes, RuntimeConfigurationObject, ScaleType # type: ignore[import-untyped] +from scalecodec.types import GenericCall, GenericExtrinsic, MultiAccountId, GenericRuntimeCallDefinition # type: ignore[import-untyped] +from scalecodec.type_registry import load_type_registry_preset # type: ignore[import-untyped] +from scalecodec.updater import update_type_registries # type: ignore[import-untyped] + +from substrateinterface.constants import WELL_KNOWN_STORAGE_KEYS from .extensions import Extension from .interfaces import ExtensionInterface @@ -39,9 +43,9 @@ from .exceptions import SubstrateRequestException, ConfigurationError, StorageFunctionNotFound, BlockNotFound, \ ExtrinsicNotFound, ExtensionCallNotFound -from .constants import * -from .keypair import Keypair, KeypairType, MnemonicLanguageCode -from .utils.ss58 import ss58_decode, ss58_encode, is_valid_ss58_address, get_ss58_format + +from .keypair import Keypair +from .utils.ss58 import ss58_decode, ss58_encode, is_valid_ss58_address __all__ = ['SubstrateInterface', 'ExtrinsicReceipt', 'logger'] @@ -166,9 +170,16 @@ def __init__(self, url=None, websocket=None, ss58_format=None, type_registry=Non # Initialize extension interface self.extensions = ExtensionInterface(self) - self.session = requests.Session() + self.reload_type_registry(use_remote_preset=False, auto_discover=False) + + @property + def next_request_id(self): + self.request_id += 1 + return self.request_id - self.reload_type_registry(use_remote_preset=use_remote_preset, auto_discover=auto_discover) + @cached_property + def session(self): + return ClientSession() def connect_websocket(self): """ @@ -199,10 +210,11 @@ def close(self): self.extensions.unregister_all() - def __enter__(self): + async def __aenter__(self): + await self.init_props() return self - def __exit__(self, exc_type, exc_val, exc_tb): + async def __aexit__(self, exc_type, exc_val, exc_tb): self.close() @staticmethod @@ -220,7 +232,8 @@ def debug_message(message: str): """ logger.debug(message) - def supports_rpc_method(self, name: str) -> bool: + # TODO: Check once on initialization + async def supports_rpc_method(self, name: str) -> bool: """ Check if substrate RPC supports given method Parameters @@ -233,13 +246,18 @@ def supports_rpc_method(self, name: str) -> bool: """ if self.config.get('rpc_methods') is None: self.config['rpc_methods'] = [] - result = self.rpc_request("rpc_methods", []).get('result') + result = (await self.rpc_request("rpc_methods", [])).get('result') if result: self.config['rpc_methods'] = result.get('methods', []) return name in self.config['rpc_methods'] - def rpc_request(self, method, params, result_handler=None): + async def rpc_request( + self, + method: str, + params: Any, + result_handler: Callable[..., Awaitable[None]] | None = None, + ) -> Any: """ Method that handles the actual RPC request to the Substrate node. The other implemented functions eventually use this method to perform the request. @@ -255,120 +273,133 @@ def rpc_request(self, method, params, result_handler=None): a dict with the parsed result of the request. """ - request_id = self.request_id - self.request_id += 1 + if self.websocket: + return await self.websocket_request(method=method, params=params, result_handler=result_handler) + + if result_handler: + raise ConfigurationError("Result handlers only available for websockets (ws://) connections") + return await self.http_request(method=method, params=params) + async def websocket_request(self, method: str, params: Any, result_handler: Callable | None = None) -> Any: + request_id = self.next_request_id payload = { "jsonrpc": "2.0", "method": method, "params": params, "id": request_id } + try: + self.websocket.send(orjson.dumps(payload)) + except WebSocketConnectionClosedException: + if self.config.get('auto_reconnect') and self.url: + # Try to reconnect websocket and retry rpc_request + self.debug_message("Connection Closed; Trying to reconnecting...") + self.connect_websocket() + + return await self.rpc_request(method=method, params=params, result_handler=result_handler) + else: + # websocket connection is externally created, re-raise exception + raise - self.debug_message('RPC request #{}: "{}"'.format(request_id, method)) - - if self.websocket: - try: - self.websocket.send(json.dumps(payload)) - except WebSocketConnectionClosedException: - if self.config.get('auto_reconnect') and self.url: - # Try to reconnect websocket and retry rpc_request - self.debug_message("Connection Closed; Trying to reconnecting...") - self.connect_websocket() - - return self.rpc_request(method=method, params=params, result_handler=result_handler) - else: - # websocket connection is externally created, re-raise exception - raise - - update_nr = 0 - json_body = None - subscription_id = None - - while json_body is None: - # Search for subscriptions - for message, remove_message in list_remove_iter(self.__rpc_message_queue): - - # Check if result message is matching request ID - if 'id' in message and message['id'] == request_id: + update_nr = 0 + json_body = None + subscription_id = None - remove_message() + while json_body is None: + # Search for subscriptions + for message, remove_message in list_remove_iter(self.__rpc_message_queue): - # Check if response has error - if 'error' in message: - raise SubstrateRequestException(message['error']) + # Check if result message is matching request ID + if 'id' in message and message['id'] == request_id: - # If result handler is set, pass result through and loop until handler return value is set - if callable(result_handler): + remove_message() - # Set subscription ID and only listen to messages containing this ID - subscription_id = message['result'] - self.debug_message(f"Websocket subscription [{subscription_id}] created") + # Check if response has error + if 'error' in message: + raise SubstrateRequestException(message['error']) - else: - json_body = message + # If result handler is set, pass result through and loop until handler return value is set + if callable(result_handler): - # Process subscription updates - for message, remove_message in list_remove_iter(self.__rpc_message_queue): - # Check if message is meant for this subscription - if 'params' in message and message['params']['subscription'] == subscription_id: + # Set subscription ID and only listen to messages containing this ID + subscription_id = message['result'] + self.debug_message(f"Websocket subscription [{subscription_id}] created") - remove_message() + else: + json_body = message - self.debug_message(f"Websocket result [{subscription_id} #{update_nr}]: {message}") + # Process subscription updates + for message, remove_message in list_remove_iter(self.__rpc_message_queue): + # Check if message is meant for this subscription + if 'params' in message and message['params']['subscription'] == subscription_id: - # Call result_handler with message for processing - callback_result = result_handler(message, update_nr, subscription_id) - if callback_result is not None: - json_body = callback_result + remove_message() - update_nr += 1 + self.debug_message(f"Websocket result [{subscription_id} #{update_nr}]: {message}") - # Read one more message to queue - if json_body is None: - self.__rpc_message_queue.append(json.loads(self.websocket.recv())) + # Call result_handler with message for processing + callback_result = await result_handler(message, update_nr, subscription_id) # type: ignore[misc] + if callback_result is not None: + json_body = callback_result - else: + update_nr += 1 - if result_handler: - raise ConfigurationError("Result handlers only available for websockets (ws://) connections") + # Read one more message to queue + if json_body is None: + self.__rpc_message_queue.append(orjson.loads(self.websocket.recv())) - response = self.session.request("POST", self.url, data=json.dumps(payload), headers=self.default_headers) + return json_body - if response.status_code != 200: + async def http_request(self, method, params): + payload = { + "jsonrpc": "2.0", + "method": method, + "params": params, + "id": self.next_request_id, + } + async with self.session.request("POST", self.url, data=orjson.dumps(payload), headers=self.default_headers) as response: + if response.status != 200: raise SubstrateRequestException( - "RPC request failed with HTTP status code {}".format(response.status_code)) + "RPC request failed with HTTP status code {}".format(response.status)) - json_body = response.json() + json_body = await response.json() - # Check if response has error - if 'error' in json_body: - raise SubstrateRequestException(json_body['error']) + # Check if response has error + if 'error' in json_body: + raise SubstrateRequestException(json_body['error']) return json_body + async def init_props(self): + if self.__name: + return + self.__name = (await self.rpc_request("system_name", [])).get('result') + self.__properties = (await self.rpc_request("system_properties", [])).get('result') + self.__chain = (await self.rpc_request("system_chain", [])).get('result') + self.__version = (await self.rpc_request("system_version", [])).get('result') + @property def name(self): if self.__name is None: - self.__name = self.rpc_request("system_name", []).get('result') + raise Exception('Call init_props() first') return self.__name @property def properties(self): if self.__properties is None: - self.__properties = self.rpc_request("system_properties", []).get('result') + raise Exception('Call init_props() first') return self.__properties @property def chain(self): if self.__chain is None: - self.__chain = self.rpc_request("system_chain", []).get('result') + raise Exception('Call init_props() first') return self.__chain @property def version(self): if self.__version is None: - self.__version = self.rpc_request("system_version", []).get('result') + raise Exception('Call init_props() first') return self.__version @property @@ -428,8 +459,9 @@ def implements_scaleinfo(self) -> Optional[bool]: """ if self.metadata: return self.metadata.portable_registry is not None + return None - def get_chain_head(self): + async def get_chain_head(self) -> str: """ A pass-though to existing JSONRPC method `chain_getHead` @@ -437,10 +469,10 @@ def get_chain_head(self): ------- """ - if self.supports_rpc_method("chain_getHead"): - response = self.rpc_request("chain_getHead", []) + if await self.supports_rpc_method("chain_getHead"): + response = await self.rpc_request("chain_getHead", []) else: - response = self.rpc_request("chain_getBlockHash", []) + response = await self.rpc_request("chain_getBlockHash", []) if response is not None: if 'error' in response: @@ -448,7 +480,9 @@ def get_chain_head(self): return response.get('result') - def get_chain_finalised_head(self): + return None + + async def get_chain_finalised_head(self) -> str: """ A pass-though to existing JSONRPC method `chain_getFinalizedHead` @@ -456,7 +490,7 @@ def get_chain_finalised_head(self): ------- """ - response = self.rpc_request("chain_getFinalizedHead", []) + response = await self.rpc_request("chain_getFinalizedHead", []) if response is not None: if 'error' in response: @@ -464,7 +498,9 @@ def get_chain_finalised_head(self): return response.get('result') - def get_block_hash(self, block_id: int = None) -> str: + return None + + async def get_block_hash(self, block_id: int | None = None) -> str: """ A pass-though to existing JSONRPC method `chain_getBlockHash` @@ -476,14 +512,16 @@ def get_block_hash(self, block_id: int = None) -> str: ------- """ - response = self.rpc_request("chain_getBlockHash", [block_id]) + response = await self.rpc_request("chain_getBlockHash", [block_id]) if 'error' in response: raise SubstrateRequestException(response['error']['message']) else: return response.get('result') - def get_block_number(self, block_hash: str) -> int: + return None + + async def get_block_number(self, block_hash: str) -> int: # type: ignore[return] """ A convenience method to get the block number for given block_hash @@ -495,7 +533,7 @@ def get_block_number(self, block_hash: str) -> int: ------- """ - response = self.rpc_request("chain_getHeader", [block_hash]) + response = await self.rpc_request("chain_getHeader", [block_hash]) if 'error' in response: raise SubstrateRequestException(response['error']['message']) @@ -505,7 +543,7 @@ def get_block_number(self, block_hash: str) -> int: if response['result']: return int(response['result']['number'], 16) - def get_block_metadata(self, block_hash=None, decode=True): + async def get_block_metadata(self, block_hash:str|None=None, decode:bool=True): """ A pass-though to existing JSONRPC method `state_getMetadata`. @@ -521,7 +559,7 @@ def get_block_metadata(self, block_hash=None, decode=True): params = None if block_hash: params = [block_hash] - response = self.rpc_request("state_getMetadata", params) + response = await self.rpc_request("state_getMetadata", params) if 'error' in response: raise SubstrateRequestException(response['error']['message']) @@ -536,7 +574,7 @@ def get_block_metadata(self, block_hash=None, decode=True): return response - def get_storage_by_key(self, block_hash: str, storage_key: str): + async def get_storage_by_key(self, block_hash: str, storage_key: str): """ A pass-though to existing JSONRPC method `state_getStorage` @@ -550,10 +588,10 @@ def get_storage_by_key(self, block_hash: str, storage_key: str): """ - if self.supports_rpc_method('state_getStorageAt'): - response = self.rpc_request("state_getStorageAt", [storage_key, block_hash]) + if await self.supports_rpc_method('state_getStorageAt'): + response = await self.rpc_request("state_getStorageAt", [storage_key, block_hash]) else: - response = self.rpc_request("state_getStorage", [storage_key, block_hash]) + response = await self.rpc_request("state_getStorage", [storage_key, block_hash]) if 'result' in response: return response.get('result') @@ -562,7 +600,7 @@ def get_storage_by_key(self, block_hash: str, storage_key: str): else: raise SubstrateRequestException("Unknown error occurred during retrieval of events") - def get_block_runtime_version(self, block_hash): + async def get_block_runtime_version(self, block_hash): """ Retrieve the runtime version id of given block_hash Parameters @@ -573,18 +611,18 @@ def get_block_runtime_version(self, block_hash): ------- """ - if self.supports_rpc_method("state_getRuntimeVersion"): - response = self.rpc_request("state_getRuntimeVersion", [block_hash]) + if await self.supports_rpc_method("state_getRuntimeVersion"): + response = await self.rpc_request("state_getRuntimeVersion", [block_hash]) else: - response = self.rpc_request("chain_getRuntimeVersion", [block_hash]) + response = await self.rpc_request("chain_getRuntimeVersion", [block_hash]) if 'error' in response: raise SubstrateRequestException(response['error']['message']) return response.get('result') - def generate_storage_hash(self, storage_module: str, storage_function: str, params: list = None, - hashers: list = None) -> str: + def generate_storage_hash(self, storage_module: str, storage_function: str, params: Optional[list] = None, + hashers: Optional[list] = None) -> str: """ Generate a storage key for given module/function @@ -602,7 +640,7 @@ def generate_storage_hash(self, storage_module: str, storage_function: str, para warnings.warn("Use StorageKey.generate() instead", DeprecationWarning) storage_key = StorageKey.create_from_storage_function( - storage_module, storage_function, params, runtime_config=self.runtime_config, metadata=self.metadata + storage_module, storage_function, params, runtime_config=self.runtime_config, metadata=self.metadata # type: ignore[arg-type] ) return '0x{}'.format(storage_key.data.hex()) @@ -621,7 +659,7 @@ def convert_storage_parameter(self, scale_type, value): # Runtime functions used by Substrate API - def init_runtime(self, block_hash=None, block_id=None): + async def init_runtime(self, block_hash: str | None=None, block_id:int|None=None) -> None: """ This method is used by all other methods that deals with metadata and types defined in the type registry. It optionally retrieves the block_hash when block_id is given and sets the applicable metadata for that @@ -639,6 +677,7 @@ def init_runtime(self, block_hash=None, block_id=None): ------- """ + await self.init_props() if block_id and block_hash: raise ValueError('Cannot provide block_hash and block_id at the same time') @@ -648,17 +687,17 @@ def init_runtime(self, block_hash=None, block_id=None): return if block_id is not None: - block_hash = self.get_block_hash(block_id) + block_hash = await self.get_block_hash(block_id) if not block_hash: - block_hash = self.get_chain_head() + block_hash = await self.get_chain_head() self.block_hash = block_hash self.block_id = block_id # In fact calls and storage functions are decoded against runtime of previous block, therefor retrieve # metadata and apply type registry of runtime of parent block - block_header = self.rpc_request('chain_getHeader', [self.block_hash]) + block_header = await self.rpc_request('chain_getHeader', [self.block_hash]) if block_header['result'] is None: raise BlockNotFound(f'Block not found for "{self.block_hash}"') @@ -670,7 +709,7 @@ def init_runtime(self, block_hash=None, block_id=None): else: runtime_block_hash = parent_block_hash - runtime_info = self.get_block_runtime_version(block_hash=runtime_block_hash) + runtime_info = await self.get_block_runtime_version(block_hash=runtime_block_hash) if runtime_info is None: raise SubstrateRequestException(f"No runtime information for block '{block_hash}'") @@ -694,7 +733,7 @@ def init_runtime(self, block_hash=None, block_id=None): self.debug_message('Retrieved metadata for {} from memory'.format(self.runtime_version)) self.metadata = self.__metadata_cache[self.runtime_version] else: - self.metadata = self.get_block_metadata(block_hash=runtime_block_hash, decode=True) + self.metadata = await self.get_block_metadata(block_hash=runtime_block_hash, decode=True) self.debug_message('Retrieved metadata for {} from Substrate node'.format(self.runtime_version)) # Update metadata cache @@ -719,7 +758,7 @@ def init_runtime(self, block_hash=None, block_id=None): self.runtime_config.set_active_spec_version_id(self.runtime_version) # Check and apply runtime constants - ss58_prefix_constant = self.get_constant("System", "SS58Prefix", block_hash=block_hash) + ss58_prefix_constant = await self.get_constant("System", "SS58Prefix", block_hash=block_hash) if ss58_prefix_constant: self.ss58_format = ss58_prefix_constant.value @@ -733,8 +772,8 @@ def init_runtime(self, block_hash=None, block_id=None): self.config['is_weight_v2'] = False self.runtime_config.update_type_registry_types({'Weight': 'WeightV1'}) - def query_map(self, module: str, storage_function: str, params: Optional[list] = None, block_hash: str = None, - max_results: int = None, start_key: str = None, page_size: int = 100, + async def query_map(self, module: str, storage_function: str, params: Optional[list] = None, block_hash: str | None = None, + max_results: int | None = None, start_key: str | None = None, page_size: int = 100, ignore_decoding_errors: bool = True) -> 'QueryMapResult': """ Iterates over all key-pairs located at the given module and storage_function. The storage @@ -743,7 +782,7 @@ def query_map(self, module: str, storage_function: str, params: Optional[list] = Example: ``` - result = substrate.query_map('System', 'Account', max_results=100) + result = await substrate.query_map('System', 'Account', max_results=100) for account, account_info in result: print(f"Free balance of account '{account.value}': {account_info.value['data']['free']}") @@ -767,12 +806,12 @@ def query_map(self, module: str, storage_function: str, params: Optional[list] = if block_hash is None: # Retrieve chain tip - block_hash = self.get_chain_head() + block_hash = await self.get_chain_head() if params is None: params = [] - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) metadata_pallet = self.metadata.get_metadata_pallet(module) @@ -809,7 +848,7 @@ def query_map(self, module: str, storage_function: str, params: Optional[list] = page_size = max_results # Retrieve storage keys - response = self.rpc_request(method="state_getKeysPaged", params=[prefix, page_size, start_key, block_hash]) + response = await self.rpc_request(method="state_getKeysPaged", params=[prefix, page_size, start_key, block_hash]) if 'error' in response: raise SubstrateRequestException(response['error']['message']) @@ -834,7 +873,7 @@ def concat_hash_len(key_hasher: str) -> int: last_key = result_keys[-1] # Retrieve corresponding value - response = self.rpc_request(method="state_queryStorageAt", params=[result_keys, block_hash]) + response = await self.rpc_request(method="state_queryStorageAt", params=[result_keys, block_hash]) if 'error' in response: raise SubstrateRequestException(response['error']['message']) @@ -848,7 +887,7 @@ def concat_hash_len(key_hasher: str) -> int: key_type_string.append(f'[u8; {concat_hash_len(key_hashers[n])}]') key_type_string.append(param_types[n]) - item_key_obj = self.decode_scale( + item_key_obj = await self.decode_scale( type_string=f"({', '.join(key_type_string)})", scale_bytes='0x' + item[0][len(prefix):], return_scale_obj=True, @@ -869,7 +908,7 @@ def concat_hash_len(key_hasher: str) -> int: item_key = None try: - item_value = self.decode_scale( + item_value = await self.decode_scale( type_string=value_type, scale_bytes=item[1], return_scale_obj=True, @@ -888,7 +927,7 @@ def concat_hash_len(key_hasher: str) -> int: ignore_decoding_errors=ignore_decoding_errors ) - def query_multi(self, storage_keys: List[StorageKey], block_hash: Optional[str] = None) -> list: + async def query_multi(self, storage_keys: List[StorageKey], block_hash: Optional[str] = None) -> list: """ Query multiple storage keys in one request. @@ -896,15 +935,15 @@ def query_multi(self, storage_keys: List[StorageKey], block_hash: Optional[str] ``` storage_keys = [ - substrate.create_storage_key( + await substrate.create_storage_key( "System", "Account", ["F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T"] ), - substrate.create_storage_key( + await substrate.create_storage_key( "System", "Account", ["GSEX8kR4Kz5UZGhvRUCJG93D5hhTAoVZ5tAe6Zne7V42DSi"] ) ] - result = substrate.query_multi(storage_keys) + result = await substrate.query_multi(storage_keys) ``` Parameters @@ -917,10 +956,10 @@ def query_multi(self, storage_keys: List[StorageKey], block_hash: Optional[str] list of `(storage_key, scale_obj)` tuples """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) # Retrieve corresponding value - response = self.rpc_request("state_queryStorageAt", [[s.to_hex() for s in storage_keys], block_hash]) + response = await self.rpc_request("state_queryStorageAt", [[s.to_hex() for s in storage_keys], block_hash]) if 'error' in response: raise SubstrateRequestException(response['error']['message']) @@ -940,8 +979,8 @@ def query_multi(self, storage_keys: List[StorageKey], block_hash: Optional[str] return result - def query(self, module: str, storage_function: str, params: list = None, block_hash: str = None, - subscription_handler: callable = None, raw_storage_key: bytes = None) -> ScaleType: + async def query(self, module: str, storage_function: str, params: Optional[list] = None, block_hash: str | None = None, + subscription_handler: Callable | None = None, raw_storage_key: Optional[bytes] = None) -> ScaleType: """ Retrieves the storage entry for given module, function and optional parameters at given block hash. @@ -950,7 +989,7 @@ def query(self, module: str, storage_function: str, params: list = None, block_h Example of subscription handler: ``` - def subscription_handler(obj, update_nr, subscription_id): + async def subscription_handler(obj, update_nr, subscription_id): if update_nr == 0: print('Initial data:', obj.value) @@ -984,16 +1023,16 @@ def subscription_handler(obj, update_nr, subscription_id): raise ValueError("Subscriptions can only be registered for current state; block_hash cannot be set") else: # Retrieve chain tip - block_hash = self.get_chain_head() + block_hash = await self.get_chain_head() if params is None: params = [] - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) if module == 'Substrate': # Search for 'well-known' storage keys - return self.__query_well_known(storage_function, block_hash) + return await self.__query_well_known(storage_function, block_hash) # Search storage call in metadata metadata_pallet = self.metadata.get_metadata_pallet(module) @@ -1027,17 +1066,17 @@ def subscription_handler(obj, update_nr, subscription_id): if callable(subscription_handler): # Wrap subscription handler to discard storage key arg - def result_handler(storage_key, updated_obj, update_nr, subscription_id): - return subscription_handler(updated_obj, update_nr, subscription_id) + async def result_handler(storage_key, updated_obj, update_nr, subscription_id): + return await subscription_handler(updated_obj, update_nr, subscription_id) - return self.subscribe_storage([storage_key], result_handler) + return await self.subscribe_storage([storage_key], result_handler) else: - if self.supports_rpc_method('state_getStorageAt'): - response = self.rpc_request("state_getStorageAt", [storage_key.to_hex(), block_hash]) + if await self.supports_rpc_method('state_getStorageAt'): + response = await self.rpc_request("state_getStorageAt", [storage_key.to_hex(), block_hash]) else: - response = self.rpc_request("state_getStorage", [storage_key.to_hex(), block_hash]) + response = await self.rpc_request("state_getStorage", [storage_key.to_hex(), block_hash]) if 'error' in response: raise SubstrateRequestException(response['error']['message']) @@ -1065,7 +1104,7 @@ def result_handler(storage_key, updated_obj, update_nr, subscription_id): return obj - def __query_well_known(self, name: str, block_hash: str) -> ScaleType: + async def __query_well_known(self, name: str, block_hash: str) -> ScaleType: """ Query well-known storage keys as defined in Substrate @@ -1081,7 +1120,7 @@ def __query_well_known(self, name: str, block_hash: str) -> ScaleType: if name not in WELL_KNOWN_STORAGE_KEYS: raise StorageFunctionNotFound(f'Well known storage key for "{name}" not found') - result = self.get_storage_by_key(block_hash, WELL_KNOWN_STORAGE_KEYS[name]['storage_key']) + result = await self.get_storage_by_key(block_hash, WELL_KNOWN_STORAGE_KEYS[name]['storage_key']) obj = self.runtime_config.create_scale_object( WELL_KNOWN_STORAGE_KEYS[name]['value_type_string'] ) @@ -1099,7 +1138,7 @@ def __query_well_known(self, name: str, block_hash: str) -> ScaleType: else: raise ValueError("No value to decode") - def create_storage_key(self, pallet: str, storage_function: str, params: Optional[list] = None) -> StorageKey: + async def create_storage_key(self, pallet: str, storage_function: str, params: Optional[list] = None) -> StorageKey: """ Create a `StorageKey` instance providing storage function details. See `subscribe_storage()`. @@ -1114,13 +1153,13 @@ def create_storage_key(self, pallet: str, storage_function: str, params: Optiona StorageKey """ - self.init_runtime() + await self.init_runtime() return StorageKey.create_from_storage_function( - pallet, storage_function, params, runtime_config=self.runtime_config, metadata=self.metadata + pallet, storage_function, params, runtime_config=self.runtime_config, metadata=self.metadata # type: ignore[arg-type] ) - def subscribe_storage(self, storage_keys: List[StorageKey], subscription_handler: callable): + async def subscribe_storage(self, storage_keys: List[StorageKey], subscription_handler: Callable): """ Subscribe to provided storage_keys and keep tracking until `subscription_handler` returns a value @@ -1134,7 +1173,7 @@ def subscribe_storage(self, storage_keys: List[StorageKey], subscription_handler Example of a subscription handler: ``` - def subscription_handler(storage_key, obj, update_nr, subscription_id): + async def subscription_handler(storage_key, obj, update_nr, subscription_id): if update_nr == 0: print('Initial data:', storage_key, obj.value) @@ -1151,17 +1190,17 @@ def subscription_handler(storage_key, obj, update_nr, subscription_id): Parameters ---------- storage_keys: StorageKey list of storage keys to subscribe to - subscription_handler: callable to handle value changes of subscription + subscription_handler: Callable to handle value changes of subscription Returns ------- """ - self.init_runtime() + await self.init_runtime() storage_key_map = {s.to_hex(): s for s in storage_keys} - def result_handler(message, update_nr, subscription_id): + async def result_handler(message, update_nr, subscription_id): # Process changes for change_storage_key, change_data in message['params']['result']['changes']: # Check for target storage key @@ -1189,22 +1228,22 @@ def result_handler(message, update_nr, subscription_id): updated_obj.decode(check_remaining=self.config.get('strict_scale_decode')) updated_obj.meta_info = {'result_found': result_found} - subscription_result = subscription_handler(storage_key, updated_obj, update_nr, subscription_id) + subscription_result = await subscription_handler(storage_key, updated_obj, update_nr, subscription_id) if subscription_result is not None: # Handler returned end result: unsubscribe from further updates - self.rpc_request("state_unsubscribeStorage", [subscription_id]) + await self.rpc_request("state_unsubscribeStorage", [subscription_id]) return subscription_result if not callable(subscription_handler): raise ValueError('Provided "subscription_handler" is not callable') - return self.rpc_request( + return await self.rpc_request( "state_subscribeStorage", [[s.to_hex() for s in storage_keys]], result_handler=result_handler ) - def retrieve_pending_extrinsics(self) -> list: + async def retrieve_pending_extrinsics(self) -> list: """ Retrieves and decodes pending extrinsics from the node's transaction pool @@ -1213,9 +1252,9 @@ def retrieve_pending_extrinsics(self) -> list: list of extrinsics """ - self.init_runtime() + await self.init_runtime() - result_data = self.rpc_request("author_pendingExtrinsics", []) + result_data = await self.rpc_request("author_pendingExtrinsics", []) extrinsics = [] @@ -1226,7 +1265,7 @@ def retrieve_pending_extrinsics(self) -> list: return extrinsics - def runtime_call(self, api: str, method: str, params: Union[list, dict] = None, block_hash: str = None) -> ScaleType: + async def runtime_call(self, api: str, method: str, params: Optional[Union[list, dict]] = None, block_hash: str | None = None) -> ScaleType: """ Calls a runtime API method @@ -1241,7 +1280,7 @@ def runtime_call(self, api: str, method: str, params: Union[list, dict] = None, ------- ScaleType """ - self.init_runtime() + await self.init_runtime() self.debug_message(f"Executing Runtime Call {api}.{method}") @@ -1276,7 +1315,7 @@ def runtime_call(self, api: str, method: str, params: Union[list, dict] = None, param_data += scale_obj.encode(params[param['name']]) # RPC request - result_data = self.rpc_request("state_call", [f'{api}_{method}', str(param_data), block_hash]) + result_data = await self.rpc_request("state_call", [f'{api}_{method}', str(param_data), block_hash]) # Decode result result_obj = self.runtime_config.create_scale_object(runtime_call_def['type']) @@ -1284,7 +1323,7 @@ def runtime_call(self, api: str, method: str, params: Union[list, dict] = None, return result_obj - def get_events(self, block_hash: str = None) -> list: + async def get_events(self, block_hash: str | None = None) -> list: """ Convenience method to get events for a certain block (storage call for module 'System' and function 'Events') @@ -1299,14 +1338,14 @@ def get_events(self, block_hash: str = None) -> list: events = [] if not block_hash: - block_hash = self.get_chain_head() + block_hash = await self.get_chain_head() - storage_obj = self.query(module="System", storage_function="Events", block_hash=block_hash) + storage_obj = await self.query(module="System", storage_function="Events", block_hash=block_hash) if storage_obj: events += storage_obj.elements return events - def get_metadata(self, block_hash=None): + async def get_metadata(self, block_hash=None): """ Returns `MetadataVersioned` object for given block_hash or chaintip if block_hash is omitted @@ -1319,11 +1358,11 @@ def get_metadata(self, block_hash=None): ------- MetadataVersioned """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) return self.metadata - def get_runtime_metadata(self, block_hash=None): + async def get_runtime_metadata(self, block_hash=None): """ Retrieves and decodes the metadata for given block or chaintip if block_hash is omitted. @@ -1340,7 +1379,7 @@ def get_runtime_metadata(self, block_hash=None): params = None if block_hash: params = [block_hash] - response = self.rpc_request("state_getMetadata", params) + response = await self.rpc_request("state_getMetadata", params) if 'error' in response: raise SubstrateRequestException(response['error']['message']) @@ -1352,8 +1391,8 @@ def get_runtime_metadata(self, block_hash=None): return response - def create_scale_object( - self, type_string: str, data: ScaleBytes = None, block_hash: str = None, **kwargs + async def create_scale_object( + self, type_string: str, data: Optional[ScaleBytes] = None, block_hash: str | None = None, **kwargs ) -> 'ScaleType': """ Convenience method to create a SCALE object of type `type_string`, this will initialize the runtime @@ -1370,15 +1409,15 @@ def create_scale_object( ------- ScaleType """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) if 'metadata' not in kwargs: kwargs['metadata'] = self.metadata return self.runtime_config.create_scale_object(type_string, data=data, **kwargs) - def compose_call( - self, call_module: str, call_function: str, call_params: dict = None, block_hash: str = None + async def compose_call( + self, call_module: str, call_function: str, call_params: dict | None = None, block_hash: str | None = None ) -> GenericCall: """ Composes a call payload which can be used in an extrinsic. @@ -1398,7 +1437,7 @@ def compose_call( if call_params is None: call_params = {} - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) call = self.runtime_config.create_scale_object( type_string='Call', metadata=self.metadata @@ -1412,7 +1451,7 @@ def compose_call( return call - def get_account_nonce(self, account_address) -> int: + async def get_account_nonce(self, account_address) -> int: """ Returns current nonce for given account address @@ -1424,18 +1463,18 @@ def get_account_nonce(self, account_address) -> int: ------- int """ - if self.supports_rpc_method('state_call'): - nonce_obj = self.runtime_call("AccountNonceApi", "account_nonce", [account_address]) + if await self.supports_rpc_method('state_call'): + nonce_obj = await self.runtime_call("AccountNonceApi", "account_nonce", [account_address]) return nonce_obj.value else: - response = self.rpc_request("system_accountNextIndex", [account_address]) + response = await self.rpc_request("system_accountNextIndex", [account_address]) return response.get('result', 0) - def generate_signature_payload(self, call: GenericCall, era=None, nonce: int = 0, tip: int = 0, - tip_asset_id: int = None, include_call_length: bool = False) -> ScaleBytes: + async def generate_signature_payload(self, call: GenericCall, era=None, nonce: int = 0, tip: int = 0, + tip_asset_id: int | None = None, include_call_length: bool = False) -> ScaleBytes: # Retrieve genesis hash - genesis_hash = self.get_block_hash(0) + genesis_hash = await self.get_block_hash(0) if not era: era = '00' @@ -1451,7 +1490,7 @@ def generate_signature_payload(self, call: GenericCall, era=None, nonce: int = 0 raise ValueError('The era dict must contain either "current" or "phase" element to encode a valid era') era_obj.encode(era) - block_hash = self.get_block_hash(block_id=era_obj.birth(era.get('current'))) + block_hash = await self.get_block_hash(block_id=era_obj.birth(era.get('current'))) # Create signature payload signature_payload = self.runtime_config.create_scale_object('ExtrinsicPayloadValue') @@ -1554,9 +1593,9 @@ def generate_signature_payload(self, call: GenericCall, era=None, nonce: int = 0 return signature_payload.data - def create_signed_extrinsic( - self, call: GenericCall, keypair: Keypair, era: dict = None, nonce: int = None, - tip: int = 0, tip_asset_id: int = None, signature: Union[bytes, str] = None + async def create_signed_extrinsic( + self, call: GenericCall, keypair: Keypair, era: dict | None = None, nonce: int | None = None, + tip: int = 0, tip_asset_id: int | None = None, signature: Optional[Union[bytes, str]] = None ) -> GenericExtrinsic: """ Creates an extrinsic signed by given account details @@ -1576,7 +1615,7 @@ def create_signed_extrinsic( GenericExtrinsic The signed Extrinsic """ - self.init_runtime() + await self.init_runtime() # Check requirements if not isinstance(call, GenericCall): @@ -1590,15 +1629,15 @@ def create_signed_extrinsic( # Retrieve nonce if nonce is None: - nonce = self.get_account_nonce(keypair.ss58_address) or 0 + nonce = await self.get_account_nonce(keypair.ss58_address) or 0 # Process era if era is None: - era = '00' + era = '00' # type: ignore[assignment] else: if isinstance(era, dict) and 'current' not in era and 'phase' not in era: # Retrieve current block id - era['current'] = self.get_block_number(self.get_chain_finalised_head()) + era['current'] = await self.get_block_number(await self.get_chain_finalised_head()) if signature is not None: @@ -1614,7 +1653,7 @@ def create_signed_extrinsic( else: # Create signature payload - signature_payload = self.generate_signature_payload( + signature_payload = await self.generate_signature_payload( call=call, era=era, nonce=nonce, tip=tip, tip_asset_id=tip_asset_id ) @@ -1628,8 +1667,8 @@ def create_signed_extrinsic( extrinsic = self.runtime_config.create_scale_object(type_string='Extrinsic', metadata=self.metadata) value = { - 'account_id': f'0x{keypair.public_key.hex()}', - 'signature': f'0x{signature.hex()}', + 'account_id': f'0x{keypair.public_key.hex()}', # type: ignore[union-attr] + 'signature': f'0x{signature.hex()}', # type: ignore[union-attr] 'call_function': call.value['call_function'], 'call_module': call.value['call_module'], 'call_args': call.value['call_args'], @@ -1649,7 +1688,7 @@ def create_signed_extrinsic( return extrinsic - def create_unsigned_extrinsic(self, call: GenericCall) -> GenericExtrinsic: + async def create_unsigned_extrinsic(self, call: GenericCall) -> GenericExtrinsic: """ Create unsigned extrinsic for given `Call` Parameters @@ -1661,7 +1700,7 @@ def create_unsigned_extrinsic(self, call: GenericCall) -> GenericExtrinsic: GenericExtrinsic """ - self.init_runtime() + await self.init_runtime() # Create extrinsic extrinsic = self.runtime_config.create_scale_object(type_string='Extrinsic', metadata=self.metadata) @@ -1693,9 +1732,9 @@ def generate_multisig_account(self, signatories: list, threshold: int) -> MultiA return multi_sig_account - def create_multisig_extrinsic(self, call: GenericCall, keypair: Keypair, multisig_account: MultiAccountId, - max_weight: Optional[Union[dict, int]] = None, era: dict = None, nonce: int = None, - tip: int = 0, tip_asset_id: int = None, signature: Union[bytes, str] = None + async def create_multisig_extrinsic(self, call: GenericCall, keypair: Keypair, multisig_account: MultiAccountId, + max_weight: Optional[Union[dict, int]] = None, era: dict | None = None, nonce: int | None = None, + tip: int = 0, tip_asset_id: int | None = None, signature: Optional[Union[bytes, str]] = None ) -> GenericExtrinsic: """ Create a Multisig extrinsic that will be signed by one of the signatories. Checks on-chain if the threshold @@ -1718,11 +1757,11 @@ def create_multisig_extrinsic(self, call: GenericCall, keypair: Keypair, multisi GenericExtrinsic """ if max_weight is None: - payment_info = self.get_payment_info(call, keypair) + payment_info = await self.get_payment_info(call, keypair) max_weight = payment_info["weight"] # Check if call has existing approvals - multisig_details = self.query("Multisig", "Multisigs", [multisig_account.value, call.call_hash]) + multisig_details = await self.query("Multisig", "Multisigs", [multisig_account.value, call.call_hash]) if multisig_details.value: maybe_timepoint = multisig_details.value['when'] @@ -1731,8 +1770,8 @@ def create_multisig_extrinsic(self, call: GenericCall, keypair: Keypair, multisi # Compose 'as_multi' when final, 'approve_as_multi' otherwise if multisig_details.value and len(multisig_details.value['approvals']) + 1 == multisig_account.threshold: - multi_sig_call = self.compose_call("Multisig", "as_multi", { - 'other_signatories': [s for s in multisig_account.signatories if s != f'0x{keypair.public_key.hex()}'], + multi_sig_call = await self.compose_call("Multisig", "as_multi", { + 'other_signatories': [s for s in multisig_account.signatories if s != f'0x{keypair.public_key.hex()}'], # type: ignore[union-attr] 'threshold': multisig_account.threshold, 'maybe_timepoint': maybe_timepoint, 'call': call, @@ -1740,19 +1779,19 @@ def create_multisig_extrinsic(self, call: GenericCall, keypair: Keypair, multisi 'max_weight': max_weight }) else: - multi_sig_call = self.compose_call("Multisig", "approve_as_multi", { - 'other_signatories': [s for s in multisig_account.signatories if s != f'0x{keypair.public_key.hex()}'], + multi_sig_call = await self.compose_call("Multisig", "approve_as_multi", { + 'other_signatories': [s for s in multisig_account.signatories if s != f'0x{keypair.public_key.hex()}'], # type: ignore[union-attr] 'threshold': multisig_account.threshold, 'maybe_timepoint': maybe_timepoint, 'call_hash': call.call_hash, 'max_weight': max_weight }) - return self.create_signed_extrinsic( + return await self.create_signed_extrinsic( multi_sig_call, keypair, era=era, nonce=nonce, tip=tip, tip_asset_id=tip_asset_id, signature=signature ) - def submit_extrinsic(self, extrinsic: GenericExtrinsic, wait_for_inclusion: bool = False, + async def submit_extrinsic(self, extrinsic: GenericExtrinsic, wait_for_inclusion: bool = False, wait_for_finalization: bool = False) -> "ExtrinsicReceipt": """ Submit an extrinsic to the connected node, with the possibility to wait until the extrinsic is included @@ -1775,7 +1814,7 @@ def submit_extrinsic(self, extrinsic: GenericExtrinsic, wait_for_inclusion: bool if not isinstance(extrinsic, GenericExtrinsic): raise TypeError("'extrinsic' must be of type Extrinsics") - def result_handler(message, update_nr, subscription_id): + async def result_handler(message, update_nr, subscription_id): # Check if extrinsic is included and finalized if 'params' in message and type(message['params']['result']) is dict: @@ -1783,14 +1822,14 @@ def result_handler(message, update_nr, subscription_id): message_result = {k.lower(): v for k, v in message['params']['result'].items()} if 'finalized' in message_result and wait_for_finalization: - self.rpc_request('author_unwatchExtrinsic', [subscription_id]) + await self.rpc_request('author_unwatchExtrinsic', [subscription_id]) return { 'block_hash': message_result['finalized'], 'extrinsic_hash': '0x{}'.format(extrinsic.extrinsic_hash.hex()), 'finalized': True } elif 'inblock' in message_result and wait_for_inclusion and not wait_for_finalization: - self.rpc_request('author_unwatchExtrinsic', [subscription_id]) + await self.rpc_request('author_unwatchExtrinsic', [subscription_id]) return { 'block_hash': message_result['inblock'], 'extrinsic_hash': '0x{}'.format(extrinsic.extrinsic_hash.hex()), @@ -1798,7 +1837,7 @@ def result_handler(message, update_nr, subscription_id): } if wait_for_inclusion or wait_for_finalization: - response = self.rpc_request( + response = await self.rpc_request( "author_submitAndWatchExtrinsic", [str(extrinsic.data)], result_handler=result_handler @@ -1813,7 +1852,7 @@ def result_handler(message, update_nr, subscription_id): else: - response = self.rpc_request("author_submitExtrinsic", [str(extrinsic.data)]) + response = await self.rpc_request("author_submitExtrinsic", [str(extrinsic.data)]) if 'result' not in response: raise SubstrateRequestException(response.get('error')) @@ -1825,7 +1864,7 @@ def result_handler(message, update_nr, subscription_id): return result - def get_payment_info(self, call: GenericCall, keypair: Keypair): + async def get_payment_info(self, call: GenericCall, keypair: Keypair): """ Retrieves fee estimation via RPC for given extrinsic @@ -1853,22 +1892,22 @@ def get_payment_info(self, call: GenericCall, keypair: Keypair): signature = '0x' + '00' * 64 # Create extrinsic - extrinsic = self.create_signed_extrinsic( + extrinsic = await self.create_signed_extrinsic( call=call, keypair=keypair, signature=signature ) - if self.supports_rpc_method('state_call'): + if await self.supports_rpc_method('state_call'): extrinsic_len = self.runtime_config.create_scale_object('u32') extrinsic_len.encode(len(extrinsic.data)) - result = self.runtime_call("TransactionPaymentApi", "query_info", [extrinsic, extrinsic_len]) + result = await self.runtime_call("TransactionPaymentApi", "query_info", [extrinsic, extrinsic_len]) return result.value else: # Backwards compatibility; deprecated RPC method - payment_info = self.rpc_request('payment_queryInfo', [str(extrinsic.data)]) + payment_info = await self.rpc_request('payment_queryInfo', [str(extrinsic.data)]) # convert partialFee to int if 'result' in payment_info: @@ -1890,7 +1929,7 @@ def get_payment_info(self, call: GenericCall, keypair: Keypair): else: raise SubstrateRequestException(payment_info['error']['message']) - def get_type_registry(self, block_hash: str = None, max_recursion: int = 4) -> dict: + async def get_type_registry(self, block_hash: str | None = None, max_recursion: int = 4) -> dict: """ Generates an exhaustive list of which RUST types exist in the runtime specified at given block_hash (or chaintip if block_hash is omitted) @@ -1906,7 +1945,7 @@ def get_type_registry(self, block_hash: str = None, max_recursion: int = 4) -> d ------- dict """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) if not self.implements_scaleinfo(): raise NotImplementedError("MetadataV14 or higher runtimes is required") @@ -1927,7 +1966,7 @@ def get_type_registry(self, block_hash: str = None, max_recursion: int = 4) -> d return type_registry - def get_type_definition(self, type_string: str, block_hash: str = None): + async def get_type_definition(self, type_string: str, block_hash: str | None = None): """ Retrieves SCALE encoding specifications of given type_string @@ -1940,10 +1979,10 @@ def get_type_definition(self, type_string: str, block_hash: str = None): ------- """ - scale_obj = self.create_scale_object(type_string, block_hash=block_hash) + scale_obj = await self.create_scale_object(type_string, block_hash=block_hash) return scale_obj.generate_type_decomposition() - def get_metadata_modules(self, block_hash=None): + async def get_metadata_modules(self, block_hash=None): """ Retrieves a list of modules in metadata for given block_hash (or chaintip if block_hash is omitted) @@ -1955,7 +1994,7 @@ def get_metadata_modules(self, block_hash=None): ------- """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) return [{ 'metadata_index': idx, @@ -1969,7 +2008,7 @@ def get_metadata_modules(self, block_hash=None): 'count_errors': len(module.errors or []), } for idx, module in enumerate(self.metadata.pallets)] - def get_metadata_module(self, name, block_hash=None): + async def get_metadata_module(self, name, block_hash=None): """ Retrieves modules in metadata by name for given block_hash (or chaintip if block_hash is omitted) @@ -1982,11 +2021,11 @@ def get_metadata_module(self, name, block_hash=None): ------- MetadataModule """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) return self.metadata.get_metadata_pallet(name) - def get_metadata_call_functions(self, block_hash=None) -> list: + async def get_metadata_call_functions(self, block_hash=None) -> list: """ Retrieves a list of all call functions in metadata active for given block_hash (or chaintip if block_hash is omitted) @@ -1998,7 +2037,7 @@ def get_metadata_call_functions(self, block_hash=None) -> list: ------- list """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) call_list = [] @@ -2014,7 +2053,7 @@ def get_metadata_call_functions(self, block_hash=None) -> list: return call_list - def get_metadata_call_function(self, module_name: str, call_function_name: str, block_hash: str = None): + async def get_metadata_call_function(self, module_name: str, call_function_name: str, block_hash: str | None = None): """ Retrieves the details of a call function given module name, call function name and block_hash (or chaintip if block_hash is omitted) @@ -2029,7 +2068,7 @@ def get_metadata_call_function(self, module_name: str, call_function_name: str, ------- """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) for pallet in self.metadata.pallets: if pallet.name == module_name and pallet.calls: @@ -2037,7 +2076,7 @@ def get_metadata_call_function(self, module_name: str, call_function_name: str, if call.name == call_function_name: return call - def get_metadata_events(self, block_hash=None) -> list: + async def get_metadata_events(self, block_hash=None) -> list: """ Retrieves a list of all events in metadata active for given block_hash (or chaintip if block_hash is omitted) @@ -2050,7 +2089,7 @@ def get_metadata_events(self, block_hash=None) -> list: list """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) event_list = [] @@ -2063,7 +2102,7 @@ def get_metadata_events(self, block_hash=None) -> list: return event_list - def get_metadata_event(self, module_name, event_name, block_hash=None): + async def get_metadata_event(self, module_name, event_name, block_hash=None): """ Retrieves the details of an event for given module name, call function name and block_hash (or chaintip if block_hash is omitted) @@ -2079,7 +2118,7 @@ def get_metadata_event(self, module_name, event_name, block_hash=None): """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) for pallet in self.metadata.pallets: if pallet.name == module_name and pallet.events: @@ -2087,7 +2126,7 @@ def get_metadata_event(self, module_name, event_name, block_hash=None): if event.name == event_name: return event - def get_metadata_constants(self, block_hash=None) -> list: + async def get_metadata_constants(self, block_hash=None) -> list: """ Retrieves a list of all constants in metadata active at given block_hash (or chaintip if block_hash is omitted) @@ -2100,7 +2139,7 @@ def get_metadata_constants(self, block_hash=None) -> list: list """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) constant_list = [] @@ -2114,7 +2153,7 @@ def get_metadata_constants(self, block_hash=None) -> list: return constant_list - def get_metadata_constant(self, module_name, constant_name, block_hash=None): + async def get_metadata_constant(self, module_name, constant_name, block_hash=None): """ Retrieves the details of a constant for given module name, call function name and block_hash (or chaintip if block_hash is omitted) @@ -2130,7 +2169,7 @@ def get_metadata_constant(self, module_name, constant_name, block_hash=None): MetadataModuleConstants """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) for module_idx, module in enumerate(self.metadata.pallets): @@ -2140,7 +2179,9 @@ def get_metadata_constant(self, module_name, constant_name, block_hash=None): if constant_name == constant.value['name']: return constant - def get_constant(self, module_name, constant_name, block_hash=None) -> Optional[ScaleType]: + return None + + async def get_constant(self, module_name, constant_name, block_hash=None) -> Optional[ScaleType]: # type: ignore[return] """ Returns the decoded `ScaleType` object of the constant for given module name, call function name and block_hash (or chaintip if block_hash is omitted) @@ -2156,14 +2197,14 @@ def get_constant(self, module_name, constant_name, block_hash=None) -> Optional[ ScaleType """ - constant = self.get_metadata_constant(module_name, constant_name, block_hash=block_hash) + constant = await self.get_metadata_constant(module_name, constant_name, block_hash=block_hash) if constant: # Decode to ScaleType - return self.decode_scale( + return await self.decode_scale( constant.type, ScaleBytes(constant.constant_value), block_hash=block_hash, return_scale_obj=True ) - def get_metadata_storage_functions(self, block_hash=None) -> list: + async def get_metadata_storage_functions(self, block_hash=None) -> list: """ Retrieves a list of all storage functions in metadata active at given block_hash (or chaintip if block_hash is omitted) @@ -2176,7 +2217,7 @@ def get_metadata_storage_functions(self, block_hash=None) -> list: ------- list """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) storage_list = [] @@ -2193,7 +2234,7 @@ def get_metadata_storage_functions(self, block_hash=None) -> list: return storage_list - def get_metadata_storage_function(self, module_name, storage_name, block_hash=None): + async def get_metadata_storage_function(self, module_name, storage_name, block_hash=None): """ Retrieves the details of a storage function for given module name, call function name and block_hash @@ -2207,14 +2248,14 @@ def get_metadata_storage_function(self, module_name, storage_name, block_hash=No ------- """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) pallet = self.metadata.get_metadata_pallet(module_name) if pallet: return pallet.get_storage_function(storage_name) - def get_metadata_errors(self, block_hash=None) -> list: + async def get_metadata_errors(self, block_hash=None) -> list: """ Retrieves a list of all errors in metadata active at given block_hash (or chaintip if block_hash is omitted) @@ -2226,7 +2267,7 @@ def get_metadata_errors(self, block_hash=None) -> list: ------- list """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) error_list = [] @@ -2241,7 +2282,7 @@ def get_metadata_errors(self, block_hash=None) -> list: return error_list - def get_metadata_error(self, module_name, error_name, block_hash=None): + async def get_metadata_error(self, module_name, error_name, block_hash=None): """ Retrieves the details of an error for given module name, call function name and block_hash @@ -2255,7 +2296,7 @@ def get_metadata_error(self, module_name, error_name, block_hash=None): ------- """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) for module_idx, module in enumerate(self.metadata.pallets): if module.name == module_name and module.errors: @@ -2263,7 +2304,7 @@ def get_metadata_error(self, module_name, error_name, block_hash=None): if error_name == error.name: return error - def get_metadata_runtime_call_functions(self) -> list: + async def get_metadata_runtime_call_functions(self) -> list: """ Get a list of available runtime API calls @@ -2271,16 +2312,16 @@ def get_metadata_runtime_call_functions(self) -> list: ------- list """ - self.init_runtime() + await self.init_runtime() call_functions = [] for api, methods in self.runtime_config.type_registry["runtime_api"].items(): for method in methods["methods"].keys(): - call_functions.append(self.get_metadata_runtime_call_function(api, method)) + call_functions.append(await self.get_metadata_runtime_call_function(api, method)) return call_functions - def get_metadata_runtime_call_function(self, api: str, method: str) -> GenericRuntimeCallDefinition: + async def get_metadata_runtime_call_function(self, api: str, method: str) -> GenericRuntimeCallDefinition: """ Get details of a runtime API call @@ -2293,7 +2334,7 @@ def get_metadata_runtime_call_function(self, api: str, method: str) -> GenericRu ------- GenericRuntimeCallDefinition """ - self.init_runtime() + await self.init_runtime() try: runtime_call_def = self.runtime_config.type_registry["runtime_api"][api]['methods'][method] @@ -2306,21 +2347,21 @@ def get_metadata_runtime_call_function(self, api: str, method: str) -> GenericRu # Add runtime API types to registry self.runtime_config.update_type_registry_types(runtime_api_types) - runtime_call_def_obj = self.create_scale_object("RuntimeCallDefinition") + runtime_call_def_obj = await self.create_scale_object("RuntimeCallDefinition") runtime_call_def_obj.encode(runtime_call_def) return runtime_call_def_obj - def __get_block_handler(self, block_hash: str, ignore_decoding_errors: bool = False, include_author: bool = False, + async def __get_block_handler(self, block_hash: str, ignore_decoding_errors: bool = False, include_author: bool = False, header_only: bool = False, finalized_only: bool = False, - subscription_handler: callable = None): + subscription_handler: Callable | None = None): try: - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) except BlockNotFound: return None - def decode_block(block_data, block_data_hash=None): + async def decode_block(block_data, block_data_hash=None): if block_data: if block_data_hash: @@ -2343,7 +2384,7 @@ def decode_block(block_data, block_data_hash=None): extrinsic_decoder.decode(check_remaining=self.config.get('strict_scale_decode')) block_data['extrinsics'][idx] = extrinsic_decoder - except Exception as e: + except Exception: if not ignore_decoding_errors: raise block_data['extrinsics'][idx] = None @@ -2369,7 +2410,7 @@ def decode_block(block_data, block_data_hash=None): engine = bytes(log_digest[1][0]) # Retrieve validator set parent_hash = block_data['header']['parentHash'] - validator_set = self.query("Session", "Validators", block_hash=parent_hash) + validator_set = await self.query("Session", "Validators", block_hash=parent_hash) if engine == b'BABE': babe_predigest = self.runtime_config.create_scale_object( @@ -2403,7 +2444,7 @@ def decode_block(block_data, block_data_hash=None): else: if log_digest.value['PreRuntime']['engine'] == 'BABE': - validator_set = self.query("Session", "Validators", block_hash=block_hash) + validator_set = await self.query("Session", "Validators", block_hash=block_hash) rank_validator = log_digest.value['PreRuntime']['data']['authority_index'] block_author = validator_set.elements[rank_validator] @@ -2424,33 +2465,33 @@ def decode_block(block_data, block_data_hash=None): rpc_method_prefix = 'Finalized' if finalized_only else 'New' - def result_handler(message, update_nr, subscription_id): + async def result_handler(message, update_nr, subscription_id): - new_block = decode_block({'header': message['params']['result']}) + new_block = await decode_block({'header': message['params']['result']}) - subscription_result = subscription_handler(new_block, update_nr, subscription_id) + subscription_result = await subscription_handler(new_block, update_nr, subscription_id) if subscription_result is not None: # Handler returned end result: unsubscribe from further updates - self.rpc_request(f"chain_unsubscribe{rpc_method_prefix}Heads", [subscription_id]) + await self.rpc_request(f"chain_unsubscribe{rpc_method_prefix}Heads", [subscription_id]) return subscription_result - result = self.rpc_request(f"chain_subscribe{rpc_method_prefix}Heads", [], result_handler=result_handler) + result = await self.rpc_request(f"chain_subscribe{rpc_method_prefix}Heads", [], result_handler=result_handler) return result else: if header_only: - response = self.rpc_request('chain_getHeader', [block_hash]) - return decode_block({'header': response['result']}, block_data_hash=block_hash) + response = await self.rpc_request('chain_getHeader', [block_hash]) + return await decode_block({'header': response['result']}, block_data_hash=block_hash) else: - response = self.rpc_request('chain_getBlock', [block_hash]) - return decode_block(response['result']['block'], block_data_hash=block_hash) + response = await self.rpc_request('chain_getBlock', [block_hash]) + return await decode_block(response['result']['block'], block_data_hash=block_hash) - def get_block(self, block_hash: str = None, block_number: int = None, ignore_decoding_errors: bool = False, + async def get_block(self, block_hash: str | None = None, block_number: int | None = None, ignore_decoding_errors: bool = False, include_author: bool = False, finalized_only: bool = False) -> Optional[dict]: """ Retrieves a block and decodes its containing extrinsics and log digest items. If `block_hash` and `block_number` @@ -2474,7 +2515,7 @@ def get_block(self, block_hash: str = None, block_number: int = None, ignore_dec raise ValueError('Either block_hash or block_number should be be set') if block_number is not None: - block_hash = self.get_block_hash(block_number) + block_hash = await self.get_block_hash(block_number) if block_hash is None: return @@ -2485,16 +2526,16 @@ def get_block(self, block_hash: str = None, block_number: int = None, ignore_dec if block_hash is None: # Retrieve block hash if finalized_only: - block_hash = self.get_chain_finalised_head() + block_hash = await self.get_chain_finalised_head() else: - block_hash = self.get_chain_head() + block_hash = await self.get_chain_head() - return self.__get_block_handler( + return await self.__get_block_handler( block_hash=block_hash, ignore_decoding_errors=ignore_decoding_errors, header_only=False, include_author=include_author ) - def get_block_header(self, block_hash: str = None, block_number: int = None, ignore_decoding_errors: bool = False, + async def get_block_header(self, block_hash: str | None = None, block_number: int | None = None, ignore_decoding_errors: bool = False, include_author: bool = False, finalized_only: bool = False): """ Retrieves a block header and decodes its containing log digest items. If `block_hash` and `block_number` @@ -2520,7 +2561,7 @@ def get_block_header(self, block_hash: str = None, block_number: int = None, ign raise ValueError('Either block_hash or block_number should be be set') if block_number is not None: - block_hash = self.get_block_hash(block_number) + block_hash = await self.get_block_hash(block_number) if block_hash is None: return @@ -2531,22 +2572,27 @@ def get_block_header(self, block_hash: str = None, block_number: int = None, ign if block_hash is None: # Retrieve block hash if finalized_only: - block_hash = self.get_chain_finalised_head() + block_hash = await self.get_chain_finalised_head() else: - block_hash = self.get_chain_head() + block_hash = await self.get_chain_head() else: # Check conflicting scenarios if finalized_only: raise ValueError('finalized_only cannot be True when block_hash is provided') - return self.__get_block_handler( + return await self.__get_block_handler( block_hash=block_hash, ignore_decoding_errors=ignore_decoding_errors, header_only=True, include_author=include_author ) - def subscribe_block_headers(self, subscription_handler: callable, ignore_decoding_errors: bool = False, - include_author: bool = False, finalized_only=False): + async def subscribe_block_headers( + self, + subscription_handler: Callable[..., Awaitable[None]], + ignore_decoding_errors: bool = False, + include_author: bool = False, + finalized_only=False, + ) -> None: """ Subscribe to new block headers as soon as they are available. The callable `subscription_handler` will be executed when a new block is available and execution will block until `subscription_handler` will return @@ -2555,7 +2601,7 @@ def subscribe_block_headers(self, subscription_handler: callable, ignore_decodin Example: ``` - def subscription_handler(obj, update_nr, subscription_id): + async def subscription_handler(obj, update_nr, subscription_id): print(f"New block #{obj['header']['number']} produced by {obj['header']['author']}") @@ -2563,7 +2609,7 @@ def subscription_handler(obj, update_nr, subscription_id): return {'message': 'Subscription will cancel when a value is returned', 'updates_processed': update_nr} - result = substrate.subscribe_block_headers(subscription_handler, include_author=True) + result = await substrate.subscribe_block_headers(subscription_handler, include_author=True) ``` Parameters @@ -2579,16 +2625,19 @@ def subscription_handler(obj, update_nr, subscription_id): """ # Retrieve block hash if finalized_only: - block_hash = self.get_chain_finalised_head() + block_hash = await self.get_chain_finalised_head() else: - block_hash = self.get_chain_head() + block_hash = await self.get_chain_head() - return self.__get_block_handler( - block_hash, subscription_handler=subscription_handler, ignore_decoding_errors=ignore_decoding_errors, - include_author=include_author, finalized_only=finalized_only + return await self.__get_block_handler( + block_hash=block_hash, + subscription_handler=subscription_handler, + ignore_decoding_errors=ignore_decoding_errors, + include_author=include_author, + finalized_only=finalized_only, ) - def retrieve_extrinsic_by_identifier(self, extrinsic_identifier: str) -> "ExtrinsicReceipt": + async def retrieve_extrinsic_by_identifier(self, extrinsic_identifier: str) -> "ExtrinsicReceipt": """ Retrieve an extrinsic by its identifier in format "[block_number]-[extrinsic_index]" e.g. 333456-4 @@ -2600,11 +2649,14 @@ def retrieve_extrinsic_by_identifier(self, extrinsic_identifier: str) -> "Extrin ------- ExtrinsicReceipt """ - return ExtrinsicReceipt.create_from_extrinsic_identifier( - substrate=self, extrinsic_identifier=extrinsic_identifier + receipt = await ExtrinsicReceipt.create_from_extrinsic_identifier( + substrate=self, + extrinsic_identifier=extrinsic_identifier, ) + await receipt.retrieve_extrinsic() + return receipt - def retrieve_extrinsic_by_hash(self, block_hash: str, extrinsic_hash: str) -> "ExtrinsicReceipt": + async def retrieve_extrinsic_by_hash(self, block_hash: str, extrinsic_hash: str) -> "ExtrinsicReceipt": """ Retrieve an extrinsic by providing the block_hash and the extrinsic hash @@ -2617,13 +2669,15 @@ def retrieve_extrinsic_by_hash(self, block_hash: str, extrinsic_hash: str) -> "E ------- ExtrinsicReceipt """ - return ExtrinsicReceipt( + receipt = ExtrinsicReceipt( substrate=self, block_hash=block_hash, extrinsic_hash=extrinsic_hash ) + await receipt.retrieve_extrinsic() + return receipt - def get_extrinsics(self, block_hash: str = None, block_number: int = None) -> list: + async def get_extrinsics(self, block_hash: str | None = None, block_number: int | None = None) -> list: # type: ignore[return] """ Return extrinsics for given block_hash or block_number @@ -2636,11 +2690,11 @@ def get_extrinsics(self, block_hash: str = None, block_number: int = None) -> li ------- """ - block = self.get_block(block_hash=block_hash, block_number=block_number) + block = await self.get_block(block_hash=block_hash, block_number=block_number) if block: return block['extrinsics'] - def extension_call(self, name, **kwargs): + async def extension_call(self, name, **kwargs): for extension in self.extensions: if isinstance(extension, Extension): if hasattr(extension, name): @@ -2653,19 +2707,19 @@ def extension_call(self, name, **kwargs): raise ExtensionCallNotFound(f"No extension found that implements '{name}'") - def filter_extrinsics(self, **kwargs) -> list: - return self.extension_call('filter_extrinsics', **kwargs) + async def filter_extrinsics(self, **kwargs) -> list: + return await self.extension_call('filter_extrinsics', **kwargs) - def filter_events(self, **kwargs) -> list: - return self.extension_call('filter_events', **kwargs) + async def filter_events(self, **kwargs) -> list: + return await self.extension_call('filter_events', **kwargs) - def search_block_number(self, block_datetime: datetime, block_time: int = 6) -> int: - return self.extension_call('search_block_number', block_datetime=block_datetime, block_time=block_time) + async def search_block_number(self, block_datetime: datetime, block_time: int = 6) -> int: + return await self.extension_call('search_block_number', block_datetime=block_datetime, block_time=block_time) - def get_block_timestamp(self, block_number: int) -> int: - return self.extension_call('get_block_timestamp', block_number=block_number) + async def get_block_timestamp(self, block_number: int) -> int: + return await self.extension_call('get_block_timestamp', block_number=block_number) - def decode_scale(self, type_string, scale_bytes, block_hash=None, return_scale_obj=False): + async def decode_scale(self, type_string, scale_bytes, block_hash=None, return_scale_obj=False): """ Helper function to decode arbitrary SCALE-bytes (e.g. 0x02000000) according to given RUST type_string (e.g. BlockNumber). The relevant versioning information of the type (if defined) will be applied if block_hash @@ -2682,9 +2736,9 @@ def decode_scale(self, type_string, scale_bytes, block_hash=None, return_scale_o ------- """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) - if type(scale_bytes) == str: + if isinstance(scale_bytes, str): scale_bytes = ScaleBytes(scale_bytes) obj = self.runtime_config.create_scale_object( @@ -2700,7 +2754,7 @@ def decode_scale(self, type_string, scale_bytes, block_hash=None, return_scale_o else: return obj.value - def encode_scale(self, type_string, value, block_hash=None) -> ScaleBytes: + async def encode_scale(self, type_string, value, block_hash=None) -> ScaleBytes: """ Helper function to encode arbitrary data into SCALE-bytes for given RUST type_string @@ -2714,14 +2768,14 @@ def encode_scale(self, type_string, value, block_hash=None) -> ScaleBytes: ------- ScaleBytes """ - self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) obj = self.runtime_config.create_scale_object( type_string=type_string, metadata=self.metadata ) return obj.encode(value) - def ss58_encode(self, public_key: Union[str, bytes], ss58_format: int = None) -> str: + def ss58_encode(self, public_key: Union[str, bytes], ss58_format: int | None = None) -> str: """ Helper function to encode a public key to SS58 address. @@ -3033,8 +3087,8 @@ class ExtrinsicReceipt: when retrieving triggered events or determine if extrinsic was succesfull """ - def __init__(self, substrate: SubstrateInterface, extrinsic_hash: str = None, block_hash: str = None, - block_number: int = None, extrinsic_idx: int = None, finalized=None): + def __init__(self, substrate: SubstrateInterface, extrinsic_hash: str | None = None, block_hash: str | None = None, + block_number: int | None = None, extrinsic_idx: int | None = None, finalized=None): """ Object containing information of submitted extrinsic. Block hash where extrinsic is included is required when retrieving triggered events or determine if extrinsic was succesfull @@ -3061,7 +3115,7 @@ def __init__(self, substrate: SubstrateInterface, extrinsic_hash: str = None, bl self.__weight = None self.__total_fee_amount = None - def get_extrinsic_identifier(self) -> str: + async def get_extrinsic_identifier(self) -> str: """ Returns the on-chain identifier for this extrinsic in format "[block_number]-[extrinsic_idx]" e.g. 134324-2 Returns @@ -3072,7 +3126,7 @@ def get_extrinsic_identifier(self) -> str: if self.block_hash is None: raise ValueError('Cannot create extrinsic identifier: block_hash is not set') - self.block_number = self.substrate.get_block_number(self.block_hash) + self.block_number = await self.substrate.get_block_number(self.block_hash) if self.block_number is None: raise ValueError('Cannot create extrinsic identifier: unknown block_hash') @@ -3080,7 +3134,7 @@ def get_extrinsic_identifier(self) -> str: return f'{self.block_number}-{self.extrinsic_idx}' @classmethod - def create_from_extrinsic_identifier( + async def create_from_extrinsic_identifier( cls, substrate: SubstrateInterface, extrinsic_identifier: str ) -> "ExtrinsicReceipt": """ @@ -3101,7 +3155,7 @@ def create_from_extrinsic_identifier( extrinsic_idx: int = int(id_parts[1]) # Retrieve block hash - block_hash = substrate.get_block_hash(block_number) + block_hash = await substrate.get_block_hash(block_number) return cls( substrate=substrate, @@ -3110,21 +3164,21 @@ def create_from_extrinsic_identifier( extrinsic_idx=extrinsic_idx ) - def retrieve_extrinsic(self): + async def retrieve_extrinsic(self) -> None: if not self.block_hash: raise ValueError("ExtrinsicReceipt can't retrieve events because it's unknown which block_hash it is " "included, manually set block_hash or use `wait_for_inclusion` when sending extrinsic") # Determine extrinsic idx - block = self.substrate.get_block(block_hash=self.block_hash) + block = await self.substrate.get_block(block_hash=self.block_hash) - extrinsics = block['extrinsics'] + extrinsics = block['extrinsics'] # type: ignore[index] if len(extrinsics) > 0: if self.__extrinsic_idx is None: self.__extrinsic_idx = self.__get_extrinsic_index( block_extrinsics=extrinsics, - extrinsic_hash=self.extrinsic_hash + extrinsic_hash=self.extrinsic_hash # type: ignore[arg-type] ) if self.__extrinsic_idx >= len(extrinsics): @@ -3142,7 +3196,7 @@ def extrinsic_idx(self) -> int: int """ if self.__extrinsic_idx is None: - self.retrieve_extrinsic() + raise Exception('Call retrieve_extrinsic() first') return self.__extrinsic_idx @property @@ -3155,11 +3209,10 @@ def extrinsic(self) -> GenericExtrinsic: Extrinsic """ if self.__extrinsic is None: - self.retrieve_extrinsic() + raise Exception('Call retrieve_extrinsic() first') return self.__extrinsic - @property - def triggered_events(self) -> list: + async def triggered_events(self) -> list: """ Gets triggered events for submitted extrinsic. block_hash where extrinsic is included is required, manually set block_hash or use `wait_for_inclusion` when submitting extrinsic @@ -3173,32 +3226,32 @@ def triggered_events(self) -> list: raise ValueError("ExtrinsicReceipt can't retrieve events because it's unknown which block_hash it is " "included, manually set block_hash or use `wait_for_inclusion` when sending extrinsic") - if self.extrinsic_idx is None: - self.retrieve_extrinsic() + if self.__extrinsic_idx is None: + await self.retrieve_extrinsic() - self.__triggered_events = [] + self.__triggered_events = [] # type: ignore[assignment] - for event in self.substrate.get_events(block_hash=self.block_hash): + for event in (await self.substrate.get_events(block_hash=self.block_hash)): if event.extrinsic_idx == self.extrinsic_idx: - self.__triggered_events.append(event) + self.__triggered_events.append(event) # type: ignore[attr-defined] - return self.__triggered_events + return self.__triggered_events # type: ignore[return-value] - def process_events(self): - if self.triggered_events: + async def process_events(self): + if await self.triggered_events(): self.__total_fee_amount = 0 # Process fees has_transaction_fee_paid_event = False - for event in self.triggered_events: + for event in await self.triggered_events(): if event.value['module_id'] == 'TransactionPayment' and event.value['event_id'] == 'TransactionFeePaid': self.__total_fee_amount = event.value['attributes']['actual_fee'] has_transaction_fee_paid_event = True # Process other events - for event in self.triggered_events: + for event in await self.triggered_events(): # Check events if self.substrate.implements_scaleinfo(): @@ -3355,7 +3408,7 @@ def is_success(self) -> bool: bool """ if self.__is_success is None: - self.process_events() + raise Exception('Call process_events() first') return self.__is_success @@ -3373,7 +3426,7 @@ def error_message(self) -> Optional[dict]: if self.__error_message is None: if self.is_success: return None - self.process_events() + raise Exception('Call process_events() first') return self.__error_message @property @@ -3386,7 +3439,7 @@ def weight(self) -> Union[int, dict]: int (WeightV1) or dict (WeightV2) """ if self.__weight is None: - self.process_events() + raise Exception('Call process_events() first') return self.__weight @property @@ -3400,7 +3453,7 @@ def total_fee_amount(self) -> int: int """ if self.__total_fee_amount is None: - self.process_events() + raise Exception('Call process_events() first') return self.__total_fee_amount # Helper functions @@ -3426,11 +3479,11 @@ def get(self, name): return self[name] -class QueryMapResult: +class QueryMapResult(AsyncIterator): - def __init__(self, records: list, page_size: int, module: str = None, storage_function: str = None, - params: list = None, block_hash: str = None, substrate: SubstrateInterface = None, - last_key: str = None, max_results: int = None, ignore_decoding_errors: bool = False): + def __init__(self, records: list, page_size: int, module: str | None = None, storage_function: str | None = None, + params: Optional[list] = None, block_hash: str | None = None, substrate: SubstrateInterface | None = None, + last_key: str | None = None, max_results: int | None = None, ignore_decoding_errors: bool = False): self.current_index = -1 self.records = records self.page_size = page_size @@ -3444,11 +3497,11 @@ def __init__(self, records: list, page_size: int, module: str = None, storage_fu self.ignore_decoding_errors = ignore_decoding_errors self.loading_complete = False - def retrieve_next_page(self, start_key) -> list: + async def retrieve_next_page(self, start_key) -> list: if not self.substrate: return [] - result = self.substrate.query_map(module=self.module, storage_function=self.storage_function, + result = await self.substrate.query_map(module=self.module, storage_function=self.storage_function, # type: ignore[arg-type] params=self.params, page_size=self.page_size, block_hash=self.block_hash, start_key=start_key, max_results=self.max_results, ignore_decoding_errors=self.ignore_decoding_errors) @@ -3458,24 +3511,24 @@ def retrieve_next_page(self, start_key) -> list: return result.records - def __iter__(self): + def __aiter__(self): self.current_index = -1 return self - def __next__(self): + async def __anext__(self): self.current_index += 1 if self.max_results is not None and self.current_index >= self.max_results: self.loading_complete = True - raise StopIteration + raise StopAsyncIteration if self.current_index >= len(self.records) and not self.loading_complete: # try to retrieve next page from node - self.records += self.retrieve_next_page(start_key=self.last_key) + self.records += await self.retrieve_next_page(start_key=self.last_key) if self.current_index >= len(self.records): self.loading_complete = True - raise StopIteration + raise StopAsyncIteration return self.records[self.current_index] diff --git a/substrateinterface/contracts.py b/substrateinterface/contracts.py index 2ca1ab9..93b65fd 100644 --- a/substrateinterface/contracts.py +++ b/substrateinterface/contracts.py @@ -14,17 +14,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json import os from hashlib import blake2b -from typing import Optional +from typing import Any, Optional + +import orjson from .utils import version_tuple from substrateinterface.exceptions import ExtrinsicFailedException, DeployContractFailedException, \ ContractReadFailedException, ContractMetadataParseException, StorageFunctionNotFound -from scalecodec.base import ScaleBytes, ScaleType -from scalecodec.types import GenericContractExecResult +from scalecodec.base import ScaleBytes, ScaleType # type: ignore[import-untyped] +from scalecodec.types import GenericContractExecResult # type: ignore[import-untyped] from substrateinterface.base import SubstrateInterface, Keypair, ExtrinsicReceipt __all__ = ['ContractExecutionReceipt', 'ContractMetadata', 'ContractCode', 'ContractInstance', 'ContractEvent'] @@ -45,14 +46,14 @@ def __init__(self, metadata_dict: dict, substrate: SubstrateInterface): self.metadata_version = None self.metadata_dict = metadata_dict self.substrate = substrate - self.type_registry = {} - + self.type_registry = {} # type: ignore[var-annotated] self.__type_offset = 0 - self.__parse_metadata() + async def init(self): + await self.__parse_metadata() @classmethod - def create_from_file(cls, metadata_file: str, substrate: SubstrateInterface) -> "ContractMetadata": + async def create_from_file(cls, metadata_file: str, substrate: SubstrateInterface) -> "ContractMetadata": """ Create a new ContractMetadata object using the provided metadata_file, usually generated by the command "cargo +nightly contract generate-metadata" in an ink! project @@ -68,7 +69,9 @@ def create_from_file(cls, metadata_file: str, substrate: SubstrateInterface) -> """ with open(os.path.abspath(metadata_file), 'r') as fp: metadata_string = fp.read() - return cls(json.loads(metadata_string), substrate) + res = cls(orjson.loads(metadata_string), substrate) + await res.init() + return res def __getattr__(self, item): if item in self.metadata_dict: @@ -133,7 +136,7 @@ def replace_name_with_label(obj): c["signature_topic"] = None - def __parse_metadata(self): + async def __parse_metadata(self): self.__convert_to_latest_metadata() @@ -170,7 +173,7 @@ def __parse_metadata(self): self.type_registry[idx] = self.get_type_string_for_metadata_type(idx) else: - self.substrate.init_runtime() + await self.substrate.init_runtime() portable_registry = self.substrate.runtime_config.create_scale_object('PortableRegistry') portable_registry.encode({"types": self.metadata_dict["types"]}) @@ -178,7 +181,7 @@ def __parse_metadata(self): portable_registry['types'], prefix=self.type_string_prefix ) - def generate_constructor_data(self, name, args: dict = None) -> ScaleBytes: + async def generate_constructor_data(self, name, args: dict | None = None) -> ScaleBytes: """ Compose the data field used in the "Contracts.instantiate" call, finding the selectors and encoded the args of given constructor @@ -203,7 +206,7 @@ def generate_constructor_data(self, name, args: dict = None) -> ScaleBytes: if arg['label'] not in args: raise ValueError(f"Argument \"{arg['label']}\" is missing") else: - data += self.substrate.encode_scale( + data += await self.substrate.encode_scale( type_string=self.get_type_string_for_metadata_type(arg['type']['type']), value=args[arg['label']] ) @@ -224,7 +227,7 @@ def get_type_string_for_metadata_type(self, type_id: int) -> str: ------- str """ - + # assert self.metadata_version if self.metadata_version >= 1: if type_id > len(self.metadata_dict['types']): @@ -348,7 +351,7 @@ def get_return_type_string_for_message(self, name) -> str: raise ValueError(f'Message "{name}" not found') - def generate_message_data(self, name, args: dict = None) -> ScaleBytes: + async def generate_message_data(self, name, args: dict | None = None) -> ScaleBytes: """ Compose the data field used in the "Contracts.call" call, finding the selector and encoded the args of provided message name @@ -374,7 +377,7 @@ def generate_message_data(self, name, args: dict = None) -> ScaleBytes: raise ValueError(f"Argument \"{arg['label']}\" is missing") else: - data += self.substrate.encode_scale( + data += await self.substrate.encode_scale( type_string=self.get_type_string_for_metadata_type(arg['type']['type']), value=args[arg['label']] ) @@ -403,13 +406,14 @@ def get_event_id_by_topic(self, topic: str) -> Optional[int]: for event_id, event in enumerate(self.metadata_dict['spec']['events']): if topic == event['signature_topic']: return event_id + return None # raise ValueError(f'Contract event for topic "{topic}" not found') class ContractEvent(ScaleType): - def __init__(self, *args, contract_metadata: ContractMetadata = None, **kwargs): + def __init__(self, *args, contract_metadata: Optional[ContractMetadata] = None, **kwargs): """ ScaleType class containing information about a specific Contract Event, it decodes the "data" field in the generic "Contracts.ContractExecution" event that is triggered after a successfull "Contracts.call" call. @@ -419,7 +423,7 @@ def __init__(self, *args, contract_metadata: ContractMetadata = None, **kwargs): self.event_id = None self.name = None self.docs = None - self.args = [] + self.args: list[Any] = [] super().__init__(*args, **kwargs) def process(self): @@ -465,7 +469,7 @@ def __init__(self, *args, **kwargs): @classmethod def create_from_extrinsic_receipt(cls, receipt: ExtrinsicReceipt, - contract_metadata: ContractMetadata, contract_address: str = None) -> "ContractExecutionReceipt": + contract_metadata: ContractMetadata, contract_address: str | None = None) -> "ContractExecutionReceipt": """ Promotes a ExtrinsicReceipt object to a ContractExecutionReceipt. It uses the provided ContractMetadata to decode "ContractExecution" events @@ -488,8 +492,8 @@ def create_from_extrinsic_receipt(cls, receipt: ExtrinsicReceipt, contract_address=contract_address ) - def process_events(self): - super().process_events() + async def process_events(self): + await super().process_events() if self.triggered_events: @@ -507,7 +511,7 @@ def process_events(self): for topic in event.value['topics']: event_id = self.contract_metadata.get_event_id_by_topic(topic) if event_id is not None: - event_bytes = self.substrate.create_scale_object("U8").encode(event_id).data + event_bytes = await self.substrate.create_scale_object("U8").encode(event_id).data contract_data = event_bytes + contract_data # Create contract event @@ -538,15 +542,16 @@ def process_events(self): @property def contract_events(self): if self.__contract_events is None: - self.process_events() + raise Exception('Call process_events() first') + # self.process_events() return self.__contract_events class ContractCode: - def __init__(self, code_hash: bytes = None, metadata: ContractMetadata = None, wasm_bytes: bytes = None, - substrate: SubstrateInterface = None): + def __init__(self, code_hash: Optional[bytes] = None, metadata: Optional[ContractMetadata] = None, wasm_bytes: Optional[bytes] = None, + substrate: SubstrateInterface | None = None): """ Object representing the blueprint of the contract, combining either the code hash and metadata of a contract, or the WASM bytes and metadata @@ -564,7 +569,7 @@ def __init__(self, code_hash: bytes = None, metadata: ContractMetadata = None, w self.substrate = substrate @classmethod - def create_from_contract_files(cls, wasm_file: str, metadata_file: str, + async def create_from_contract_files(cls, wasm_file: str, metadata_file: str, substrate: SubstrateInterface) -> "ContractCode": """ Create a ContractCode providing paths for the WASM binary file and metadata JSON file generated by the @@ -585,12 +590,12 @@ def create_from_contract_files(cls, wasm_file: str, metadata_file: str, wasm_bytes = fp.read() code_hash = blake2b(wasm_bytes, digest_size=32).digest() - metadata = ContractMetadata.create_from_file(metadata_file, substrate=substrate) + metadata = await ContractMetadata.create_from_file(metadata_file, substrate=substrate) return cls(code_hash=code_hash, metadata=metadata, wasm_bytes=wasm_bytes, substrate=substrate) @classmethod - def create_from_code_hash(cls, code_hash: bytes, metadata_file: str, + async def create_from_code_hash(cls, code_hash: bytes, metadata_file: str, substrate: SubstrateInterface) -> "ContractCode": """ Create a ContractCode providing an existing contract code hash and a path to the metadata JSON file @@ -606,11 +611,11 @@ def create_from_code_hash(cls, code_hash: bytes, metadata_file: str, ContractCode """ - metadata = ContractMetadata.create_from_file(metadata_file, substrate=substrate) + metadata = await ContractMetadata.create_from_file(metadata_file, substrate=substrate) return cls(code_hash=code_hash, metadata=metadata, substrate=substrate) - def upload_wasm(self, keypair: Keypair, storage_deposit_limit: int = None) -> ExtrinsicReceipt: + async def upload_wasm(self, keypair: Keypair, storage_deposit_limit: int | None = None) -> ExtrinsicReceipt: """ Created and submits an "Contracts.upload_code" extrinsic containing the WASM binary @@ -623,19 +628,20 @@ def upload_wasm(self, keypair: Keypair, storage_deposit_limit: int = None) -> Ex ------- ExtrinsicReceipt """ + assert self.substrate if not self.wasm_bytes: raise ValueError("No WASM bytes to upload") - call_function = self.substrate.get_metadata_call_function('Contracts', 'upload_code') + call_function = await self.substrate.get_metadata_call_function('Contracts', 'upload_code') if not call_function: # Try to fall back on legacy `put_code` - call_function = self.substrate.get_metadata_call_function('Contracts', 'put_code') + call_function = await self.substrate.get_metadata_call_function('Contracts', 'put_code') if not call_function: raise NotImplementedError("Couldn't find method in Contracts pallet to upload the WASM binary") - call = self.substrate.compose_call( + call = await self.substrate.compose_call( call_module="Contracts", call_function=call_function.name, call_params={ @@ -644,12 +650,12 @@ def upload_wasm(self, keypair: Keypair, storage_deposit_limit: int = None) -> Ex } ) - extrinsic = self.substrate.create_signed_extrinsic(call=call, keypair=keypair) + extrinsic = await self.substrate.create_signed_extrinsic(call=call, keypair=keypair) - return self.substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) + return await self.substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) - def deploy(self, keypair: Keypair, constructor: str, args: dict = None, value: int = 0, gas_limit: dict = None, - deployment_salt: str = None, upload_code: bool = False, storage_deposit_limit: int = None + async def deploy(self, keypair: Keypair, constructor: str, args: dict | None = None, value: int = 0, gas_limit: dict | None = None, + deployment_salt: str | None = None, upload_code: bool = False, storage_deposit_limit: int | None = None ) -> "ContractInstance": """ Deploys a new instance of the contract after it has been uploaded on-chain, with provided constructor and @@ -670,9 +676,12 @@ def deploy(self, keypair: Keypair, constructor: str, args: dict = None, value: i ------- ContractInstance """ + # FIXME: mypy + # assert self.substrate + # assert self.substrate.metadata # Lookup constructor - data = self.metadata.generate_constructor_data(name=constructor, args=args) + data = await self.metadata.generate_constructor_data(name=constructor, args=args) # type: ignore[union-attr] if gas_limit is None: gas_limit = {'ref_time': 25990000000, 'proof_size': 11990383647911208550} @@ -682,7 +691,7 @@ def deploy(self, keypair: Keypair, constructor: str, args: dict = None, value: i if not self.wasm_bytes: raise ValueError("No WASM bytes to upload") - call = self.substrate.compose_call( + call = await self.substrate.compose_call( call_module='Contracts', call_function='instantiate_with_code', call_params={ @@ -695,8 +704,9 @@ def deploy(self, keypair: Keypair, constructor: str, args: dict = None, value: i } ) else: + assert self.code_hash - call = self.substrate.compose_call( + call = await self.substrate.compose_call( call_module='Contracts', call_function='instantiate', call_params={ @@ -709,14 +719,14 @@ def deploy(self, keypair: Keypair, constructor: str, args: dict = None, value: i } ) - extrinsic = self.substrate.create_signed_extrinsic(call=call, keypair=keypair) + extrinsic = await self.substrate.create_signed_extrinsic(call=call, keypair=keypair) - result = self.substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) + result = await self.substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True) if not result.is_success: raise ExtrinsicFailedException(result.error_message) - for event in result.triggered_events: + for event in await result.triggered_events(): if self.substrate.implements_scaleinfo(): @@ -740,17 +750,16 @@ def deploy(self, keypair: Keypair, constructor: str, args: dict = None, value: i class ContractInstance: - def __init__(self, contract_address: str, metadata: ContractMetadata = None, substrate: SubstrateInterface = None): + def __init__(self, contract_address: str, metadata: Optional[ContractMetadata] = None, substrate: SubstrateInterface | None = None): self.substrate = substrate self.contract_address = contract_address self.metadata = metadata - self.init() - - def init(self): + async def init(self): + await self.metadata.init() # Determine ContractExecResult according to PalletVersion try: - pallet_version = self.substrate.query("Contracts", "PalletVersion") + pallet_version = await self.substrate.query("Contracts", "PalletVersion") if pallet_version.value <= 9: self.substrate.runtime_config.update_type_registry_types( @@ -764,8 +773,8 @@ def init(self): pass @classmethod - def create_from_address(cls, contract_address: str, metadata_file: str, - substrate: SubstrateInterface = None) -> "ContractInstance": + async def create_from_address(cls, contract_address: str, metadata_file: str, + substrate: SubstrateInterface | None = None) -> "ContractInstance": """ Create a ContractInstance object that already exists on-chain providing a SS58-address and the path to the metadata JSON of that contract @@ -781,12 +790,14 @@ def create_from_address(cls, contract_address: str, metadata_file: str, ContractInstance """ - metadata = ContractMetadata.create_from_file(metadata_file, substrate=substrate) + metadata = await ContractMetadata.create_from_file(metadata_file, substrate=substrate) # type: ignore[arg-type] - return cls(contract_address=contract_address, metadata=metadata, substrate=substrate) + res = cls(contract_address=contract_address, metadata=metadata, substrate=substrate) + await res.init() + return res - def read(self, keypair: Keypair, method: str, args: dict = None, - value: int = 0, gas_limit: int = None, block_hash: str = None) -> GenericContractExecResult: + async def read(self, keypair: Keypair, method: str, args: dict | None = None, + value: int = 0, gas_limit: int | None = None, block_hash: str | None = None) -> GenericContractExecResult: """ Used to execute non-mutable messages to for example read data from the contract using getters. Can also be used to predict gas limits and 'dry-run' the execution when a mutable message is used. @@ -806,10 +817,10 @@ def read(self, keypair: Keypair, method: str, args: dict = None, GenericContractExecResult """ - input_data = self.metadata.generate_message_data(name=method, args=args) - + input_data = await self.metadata.generate_message_data(name=method, args=args) # type: ignore[union-attr] + assert self.substrate # Execute runtime call in ContractsApi - call_result = self.substrate.runtime_call("ContractsApi", "call", { + call_result = await self.substrate.runtime_call("ContractsApi", "call", { 'dest': self.contract_address, 'gas_limit': gas_limit, 'input_data': input_data.to_hex(), @@ -823,8 +834,8 @@ def read(self, keypair: Keypair, method: str, args: dict = None, if 'Ok' in call_result['result']: try: - return_type_string = self.metadata.get_return_type_string_for_message(method) - result_scale_obj = self.substrate.create_scale_object(return_type_string) + return_type_string = self.metadata.get_return_type_string_for_message(method) # type: ignore[union-attr] + result_scale_obj = await self.substrate.create_scale_object(return_type_string) result_scale_obj.decode(ScaleBytes(call_result['result'][1]['data'].value_object)) call_result.value_object['result'].value_object[1].value_object['data'] = result_scale_obj call_result.value['result']['Ok']['data'] = result_scale_obj.value @@ -834,8 +845,8 @@ def read(self, keypair: Keypair, method: str, args: dict = None, return call_result - def exec(self, keypair: Keypair, method: str, args: dict = None, - value: int = 0, gas_limit: Optional[dict] = None, storage_deposit_limit: int = None, + async def exec(self, keypair: Keypair, method: str, args: dict | None = None, + value: int = 0, gas_limit: Optional[dict] = None, storage_deposit_limit: int | None = None, wait_for_inclusion: bool = True, wait_for_finalization: bool = False ) -> ContractExecutionReceipt: """ @@ -857,14 +868,14 @@ def exec(self, keypair: Keypair, method: str, args: dict = None, ------- ContractExecutionReceipt """ - + assert self.substrate if gas_limit is None: - gas_predit_result = self.read(keypair, method, args, value) + gas_predit_result = await self.read(keypair, method, args, value) gas_limit = gas_predit_result.gas_required - input_data = self.metadata.generate_message_data(name=method, args=args) + input_data = await self.metadata.generate_message_data(name=method, args=args) # type: ignore[union-attr] - call = self.substrate.compose_call( + call = await self.substrate.compose_call( call_module='Contracts', call_function='call', call_params={ @@ -876,10 +887,10 @@ def exec(self, keypair: Keypair, method: str, args: dict = None, } ) - extrinsic = self.substrate.create_signed_extrinsic(call=call, keypair=keypair) + extrinsic = await self.substrate.create_signed_extrinsic(call=call, keypair=keypair) - receipt = self.substrate.submit_extrinsic( + receipt = await self.substrate.submit_extrinsic( extrinsic, wait_for_inclusion=wait_for_inclusion, wait_for_finalization=wait_for_finalization ) - return ContractExecutionReceipt.create_from_extrinsic_receipt(receipt, self.metadata, self.contract_address) + return ContractExecutionReceipt.create_from_extrinsic_receipt(receipt, self.metadata, self.contract_address) # type: ignore[arg-type] diff --git a/substrateinterface/extensions.py b/substrateinterface/extensions.py index 43149b2..7d8b7aa 100644 --- a/substrateinterface/extensions.py +++ b/substrateinterface/extensions.py @@ -43,7 +43,7 @@ def init(self, substrate: 'SubstrateInterface'): ------- """ - self.substrate: 'SubstrateInterface' = substrate + self.substrate: 'SubstrateInterface' = substrate # type: ignore[no-redef] def close(self): """ @@ -75,7 +75,7 @@ class SearchExtension(Extension): Type of `Extension` that implements functionality to improve and enhance search capability """ - def filter_events(self, **kwargs) -> list: + async def filter_events(self, **kwargs) -> list: """ Filters events to match provided search criteria e.g. block range, pallet name, accountID in attributes @@ -89,7 +89,7 @@ def filter_events(self, **kwargs) -> list: """ raise NotImplementedError() - def filter_extrinsics(self, **kwargs) -> list: + async def filter_extrinsics(self, **kwargs) -> list: """ Filters extrinsics to match provided search criteria e.g. block range, pallet name, signed by accountID @@ -103,7 +103,7 @@ def filter_extrinsics(self, **kwargs) -> list: """ raise NotImplementedError() - def search_block_number(self, block_datetime: datetime, block_time: int = 6, **kwargs) -> int: + async def search_block_number(self, block_datetime: datetime, block_time: int = 6, **kwargs) -> int: """ Search corresponding block number for provided `block_datetime`. the prediction tolerance is provided with `block_time` @@ -120,7 +120,7 @@ def search_block_number(self, block_datetime: datetime, block_time: int = 6, **k """ raise NotImplementedError() - def get_block_timestamp(self, block_number: int) -> int: + async def get_block_timestamp(self, block_number: int) -> int: """ Return a UNIX timestamp for given `block_number`. @@ -140,11 +140,11 @@ class SubstrateNodeExtension(SearchExtension): Implementation of `SearchExtension` using only Substrate RPC methods. Could be significant inefficient. """ - def filter_extrinsics(self, block_start: int = None, block_end: int = None, ss58_address: str = None, - pallet_name: str = None, call_name: str = None) -> list: + async def filter_extrinsics(self, block_start: int | None = None, block_end: int | None = None, ss58_address: str | None = None, # type: ignore[override] + pallet_name: str | None = None, call_name: str | None = None) -> list: if block_end is None: - block_end = self.substrate.get_block_number(None) + block_end = await self.substrate.get_block_number(None) if block_start is None: block_start = block_end @@ -155,9 +155,9 @@ def filter_extrinsics(self, block_start: int = None, block_end: int = None, ss58 result = [] for block_number in range(block_start, block_end + 1): - block_hash = self.substrate.get_block_hash(block_number) + block_hash = await self.substrate.get_block_hash(block_number) - for extrinsic in self.substrate.get_extrinsics(block_hash=block_hash): + for extrinsic in await self.substrate.get_extrinsics(block_hash=block_hash): if pallet_name is not None and pallet_name != extrinsic.value['call']['call_module']: continue @@ -173,11 +173,11 @@ def __init__(self, max_block_range: int = 100): self.max_block_range: int = max_block_range - def filter_events(self, block_start: int = None, block_end: int = None, pallet_name: str = None, - event_name: str = None, account_id: str = None) -> list: + async def filter_events(self, block_start: int | None = None, block_end: int | None = None, pallet_name: str | None = None, # type: ignore[override] + event_name: str | None = None, account_id: str | None = None) -> list: if block_end is None: - block_end = self.substrate.get_block_number(None) + block_end = await self.substrate.get_block_number(None) if block_start is None: block_start = block_end @@ -194,8 +194,8 @@ def filter_events(self, block_start: int = None, block_end: int = None, pallet_n self.debug_message(f"Retrieving events from #{block_start} to #{block_end}") for block_number in range(block_start, block_end + 1): - block_hash = self.substrate.get_block_hash(block_number) - for event in self.substrate.get_events(block_hash=block_hash): + block_hash = await self.substrate.get_block_hash(block_number) + for event in await self.substrate.get_events(block_hash=block_hash): if pallet_name is not None and pallet_name != event.value['event']['module_id']: continue @@ -215,14 +215,14 @@ def filter_events(self, block_start: int = None, block_end: int = None, pallet_n return result - def get_block_timestamp(self, block_number: int) -> int: - extrinsics = self.filter_extrinsics( + async def get_block_timestamp(self, block_number: int) -> int: + extrinsics = await self.filter_extrinsics( block_start=block_number, block_end=block_number, pallet_name="Timestamp", call_name="set" ) return extrinsics[0].value['call']['call_args'][0]['value'] / 1000 - def search_block_number(self, block_datetime: datetime, block_time: int = 6, **kwargs) -> int: + async def search_block_number(self, block_datetime: datetime, block_time: int = 6, **kwargs) -> int: """ Search corresponding block number for provided `block_datetime`. the prediction tolerance is provided with `block_time` @@ -242,8 +242,8 @@ def search_block_number(self, block_datetime: datetime, block_time: int = 6, **k target_block_timestamp = block_datetime.timestamp() # Retrieve Timestamp extrinsic for chain tip - predicted_block_number = self.substrate.get_block_number(None) - current_timestamp = self.get_block_timestamp(predicted_block_number) + predicted_block_number = await self.substrate.get_block_number(None) + current_timestamp = await self.get_block_timestamp(predicted_block_number) current_delta = current_timestamp - target_block_timestamp self.debug_message(f"Delta {current_delta} sec with chain tip #{predicted_block_number}") @@ -258,7 +258,7 @@ def search_block_number(self, block_datetime: datetime, block_time: int = 6, **k if predicted_block_number < 0: raise ValueError(f"Requested datetime points before genesis of chain (#{predicted_block_number})") - current_timestamp = self.get_block_timestamp(predicted_block_number) + current_timestamp = await self.get_block_timestamp(predicted_block_number) # Predict target block number current_delta = current_timestamp - target_block_timestamp diff --git a/substrateinterface/key.py b/substrateinterface/key.py index c1cb6eb..0ac32d3 100644 --- a/substrateinterface/key.py +++ b/substrateinterface/key.py @@ -16,7 +16,7 @@ from hashlib import blake2b from math import ceil -from scalecodec.types import Bytes +from scalecodec.types import Bytes # type: ignore[import-untyped] RE_JUNCTION = r'(\/\/?)([^/]+)' JUNCTION_ID_LEN = 32 diff --git a/substrateinterface/keypair.py b/substrateinterface/keypair.py index e5ada59..6392368 100644 --- a/substrateinterface/keypair.py +++ b/substrateinterface/keypair.py @@ -14,11 +14,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json +import orjson -from scalecodec.utils.ss58 import ss58_encode, ss58_decode, get_ss58_format +from scalecodec.utils.ss58 import ss58_encode, ss58_decode, get_ss58_format # type: ignore[import-untyped] -from scalecodec.base import ScaleBytes +from scalecodec.base import ScaleBytes # type: ignore[import-untyped] from typing import Union, Optional import time @@ -27,9 +27,7 @@ import secrets from base64 import b64encode -import nacl.bindings -import nacl.public -from eth_keys.datatypes import PrivateKey +from substrateinterface.utils import wrap_import from .constants import DEV_PHRASE from .exceptions import ConfigurationError @@ -37,9 +35,6 @@ from .utils.ecdsa_helpers import mnemonic_to_ecdsa_private_key, ecdsa_verify, ecdsa_sign from .utils.encrypted_json import decode_pair_from_encrypted_json, encode_pair -from bip39 import bip39_to_mini_secret, bip39_generate, bip39_validate -import sr25519 -import ed25519_zebra __all__ = ['Keypair', 'KeypairType', 'MnemonicLanguageCode'] @@ -84,8 +79,8 @@ class MnemonicLanguageCode: class Keypair: - def __init__(self, ss58_address: str = None, public_key: Union[bytes, str] = None, - private_key: Union[bytes, str] = None, ss58_format: int = None, seed_hex: Union[str, bytes] = None, + def __init__(self, ss58_address: str | None = None, public_key: Optional[Union[bytes, str]] = None, + private_key: Optional[Union[bytes, str]] = None, ss58_format: int | None = None, seed_hex: Optional[Union[str, bytes]] = None, crypto_type: int = KeypairType.SR25519): """ Allows generation of Keypairs from a variety of input combination, such as a public/private key combination, @@ -117,10 +112,16 @@ def __init__(self, ss58_address: str = None, public_key: Union[bytes, str] = Non if len(private_key) != 64: raise ValueError('Secret key should be 64 bytes long') if not public_key: + with wrap_import(): + import sr25519 # type: ignore[import-untyped] + public_key = sr25519.public_from_secret_key(private_key) if self.crypto_type == KeypairType.ECDSA: - private_key_obj = PrivateKey(private_key) + with wrap_import(): + import eth_keys.datatypes + + private_key_obj = eth_keys.datatypes.PrivateKey(private_key) # type: ignore[arg-type] public_key = private_key_obj.public_key.to_address() ss58_address = private_key_obj.public_key.to_checksum_address() @@ -140,13 +141,13 @@ def __init__(self, ss58_address: str = None, public_key: Union[bytes, str] = Non if not ss58_address: ss58_address = ss58_encode(public_key, ss58_format=ss58_format) - self.ss58_format: int = ss58_format + self.ss58_format: int | None = ss58_format - self.public_key: bytes = public_key + self.public_key: bytes | None = public_key # type: ignore[assignment] - self.ss58_address: str = ss58_address + self.ss58_address: str | None = ss58_address - self.private_key: bytes = private_key + self.private_key: bytes | None = private_key # type: ignore[assignment] self.mnemonic = None @@ -164,7 +165,10 @@ def generate_mnemonic(cls, words: int = 12, language_code: str = MnemonicLanguag ------- str: Seed phrase """ - return bip39_generate(words, language_code) + with wrap_import(): + import bip39.bip39 as bip39 # type: ignore[import-untyped] + + return bip39.bip39_generate(words, language_code) @classmethod def validate_mnemonic(cls, mnemonic: str, language_code: str = MnemonicLanguageCode.ENGLISH) -> bool: @@ -180,7 +184,10 @@ def validate_mnemonic(cls, mnemonic: str, language_code: str = MnemonicLanguageC ------- bool """ - return bip39_validate(mnemonic, language_code) + with wrap_import(): + import bip39.bip39 as bip39 # type: ignore[import-untyped] + + return bip39.bip39_validate(mnemonic, language_code) @classmethod def create_from_mnemonic(cls, mnemonic: str, ss58_format=42, crypto_type=KeypairType.SR25519, @@ -208,7 +215,10 @@ def create_from_mnemonic(cls, mnemonic: str, ss58_format=42, crypto_type=Keypair keypair = cls.create_from_private_key(private_key, ss58_format=ss58_format, crypto_type=crypto_type) else: - seed_array = bip39_to_mini_secret(mnemonic, "", language_code) + with wrap_import(): + import bip39.bip39 as bip39 # type: ignore[import-untyped] + + seed_array = bip39.bip39_to_mini_secret(mnemonic, "", language_code) keypair = cls.create_from_seed( seed_hex=binascii.hexlify(bytearray(seed_array)).decode("ascii"), @@ -216,7 +226,7 @@ def create_from_mnemonic(cls, mnemonic: str, ss58_format=42, crypto_type=Keypair crypto_type=crypto_type ) - keypair.mnemonic = mnemonic + keypair.mnemonic = mnemonic # type: ignore[assignment] return keypair @@ -242,8 +252,14 @@ def create_from_seed( seed_hex = bytes.fromhex(seed_hex.replace('0x', '')) if crypto_type == KeypairType.SR25519: + with wrap_import(): + import sr25519 + public_key, private_key = sr25519.pair_from_seed(seed_hex) elif crypto_type == KeypairType.ED25519: + with wrap_import(): + import ed25519_zebra # type: ignore[import-untyped] + private_key, public_key = ed25519_zebra.ed_from_seed(seed_hex) else: raise ValueError('crypto_type "{}" not supported'.format(crypto_type)) @@ -279,7 +295,7 @@ def create_from_uri( suri_regex = re.match(r'^(?P.[^/]+( .[^/]+)*)(?P(//?[^/]+)*)(///(?P.*))?$', suri) - suri_parts = suri_regex.groupdict() + suri_parts = suri_regex.groupdict() # type: ignore[union-attr] if crypto_type == KeypairType.ECDSA: if language_code != MnemonicLanguageCode.ENGLISH: @@ -302,11 +318,14 @@ def create_from_uri( if suri_parts['path'] != '': - derived_keypair.derive_path = suri_parts['path'] + derived_keypair.derive_path = suri_parts['path'] # type: ignore[assignment] if crypto_type not in [KeypairType.SR25519]: raise NotImplementedError('Derivation paths for this crypto type not supported') + with wrap_import(): + import sr25519 + derive_junctions = extract_derive_path(suri_parts['path']) child_pubkey = derived_keypair.public_key @@ -334,8 +353,8 @@ def create_from_uri( @classmethod def create_from_private_key( - cls, private_key: Union[bytes, str], public_key: Union[bytes, str] = None, ss58_address: str = None, - ss58_format: int = None, crypto_type: int = KeypairType.SR25519 + cls, private_key: Union[bytes, str], public_key: Optional[Union[bytes, str]] = None, ss58_address: str | None = None, + ss58_format: int | None = None, crypto_type: int = KeypairType.SR25519 ) -> 'Keypair': """ Creates Keypair for specified public/private keys @@ -359,7 +378,7 @@ def create_from_private_key( @classmethod def create_from_encrypted_json(cls, json_data: Union[str, dict], passphrase: str, - ss58_format: int = None) -> 'Keypair': + ss58_format: int | None = None) -> 'Keypair': """ Create a Keypair from a PolkadotJS format encrypted JSON file @@ -375,13 +394,13 @@ def create_from_encrypted_json(cls, json_data: Union[str, dict], passphrase: str """ if type(json_data) is str: - json_data = json.loads(json_data) + json_data = orjson.loads(json_data) private_key, public_key = decode_pair_from_encrypted_json(json_data, passphrase) - if 'sr25519' in json_data['encoding']['content']: + if 'sr25519' in json_data['encoding']['content']: # type: ignore[index] crypto_type = KeypairType.SR25519 - elif 'ed25519' in json_data['encoding']['content']: + elif 'ed25519' in json_data['encoding']['content']: # type: ignore[index] crypto_type = KeypairType.ED25519 # Strip the nonce part of the private key private_key = private_key[0:32] @@ -389,11 +408,11 @@ def create_from_encrypted_json(cls, json_data: Union[str, dict], passphrase: str raise NotImplementedError("Unknown KeypairType found in JSON") if ss58_format is None and 'address' in json_data: - ss58_format = get_ss58_format(json_data['address']) + ss58_format = get_ss58_format(json_data['address']) # type: ignore[index] return cls.create_from_private_key(private_key, public_key, ss58_format=ss58_format, crypto_type=crypto_type) - def export_to_encrypted_json(self, passphrase: str, name: str = None) -> dict: + def export_to_encrypted_json(self, passphrase: str, name: str | None = None) -> dict: """ Export Keypair to PolkadotJS format encrypted JSON file @@ -406,6 +425,9 @@ def export_to_encrypted_json(self, passphrase: str, name: str = None) -> dict: ------- dict """ + with wrap_import(): + import sr25519 + if not name: name = self.ss58_address @@ -416,7 +438,7 @@ def export_to_encrypted_json(self, passphrase: str, name: str = None) -> dict: # https://github.com/polkadot-js/wasm/blob/master/packages/wasm-crypto/src/rs/sr25519.rs#L125 converted_private_key = sr25519.convert_secret_key_to_ed25519(self.private_key) - encoded = encode_pair(self.public_key, converted_private_key, passphrase) + encoded = encode_pair(self.public_key, converted_private_key, passphrase) # type: ignore[arg-type] json_data = { "encoded": b64encode(encoded).decode(), @@ -445,7 +467,7 @@ def sign(self, data: Union[ScaleBytes, bytes, str]) -> bytes: if type(data) is ScaleBytes: data = bytes(data.data) elif data[0:2] == '0x': - data = bytes.fromhex(data[2:]) + data = bytes.fromhex(data[2:]) # type: ignore[arg-type] elif type(data) is str: data = data.encode() @@ -453,13 +475,19 @@ def sign(self, data: Union[ScaleBytes, bytes, str]) -> bytes: raise ConfigurationError('No private key set to create signatures') if self.crypto_type == KeypairType.SR25519: + with wrap_import(): + import sr25519 + signature = sr25519.sign((self.public_key, self.private_key), data) elif self.crypto_type == KeypairType.ED25519: + with wrap_import(): + import ed25519_zebra + signature = ed25519_zebra.ed_sign(self.private_key, data) elif self.crypto_type == KeypairType.ECDSA: - signature = ecdsa_sign(self.private_key, data) + signature = ecdsa_sign(self.private_key, data) # type: ignore[arg-type] else: raise ConfigurationError("Crypto type not supported") @@ -483,7 +511,7 @@ def verify(self, data: Union[ScaleBytes, bytes, str], signature: Union[bytes, st if type(data) is ScaleBytes: data = bytes(data.data) elif data[0:2] == '0x': - data = bytes.fromhex(data[2:]) + data = bytes.fromhex(data[2:]) # type: ignore[arg-type] elif type(data) is str: data = data.encode() @@ -494,8 +522,14 @@ def verify(self, data: Union[ScaleBytes, bytes, str], signature: Union[bytes, st raise TypeError("Signature should be of type bytes or a hex-string") if self.crypto_type == KeypairType.SR25519: + with wrap_import(): + import sr25519 + crypto_verify_fn = sr25519.verify elif self.crypto_type == KeypairType.ED25519: + with wrap_import(): + import ed25519_zebra + crypto_verify_fn = ed25519_zebra.ed_verify elif self.crypto_type == KeypairType.ECDSA: crypto_verify_fn = ecdsa_verify @@ -507,7 +541,7 @@ def verify(self, data: Union[ScaleBytes, bytes, str], signature: Union[bytes, st if not verified: # Another attempt with the data wrapped, as discussed in https://github.com/polkadot-js/extension/pull/743 # Note: As Python apps are trusted sources on its own, no need to wrap data when signing from this lib - verified = crypto_verify_fn(signature, b'' + data + b'', self.public_key) + verified = crypto_verify_fn(signature, b'' + data + b'', self.public_key) # type: ignore[operator] return verified @@ -532,9 +566,14 @@ def encrypt_message( raise ConfigurationError('No private key set to encrypt') if self.crypto_type != KeypairType.ED25519: raise ConfigurationError('Only ed25519 keypair type supported') + + with wrap_import(): + import nacl.bindings + import nacl.public + curve25519_public_key = nacl.bindings.crypto_sign_ed25519_pk_to_curve25519(recipient_public_key) recipient = nacl.public.PublicKey(curve25519_public_key) - private_key = nacl.bindings.crypto_sign_ed25519_sk_to_curve25519(self.private_key + self.public_key) + private_key = nacl.bindings.crypto_sign_ed25519_sk_to_curve25519(self.private_key + self.public_key) # type: ignore[operator] sender = nacl.public.PrivateKey(private_key) box = nacl.public.Box(sender, recipient) return box.encrypt(message if isinstance(message, bytes) else message.encode("utf-8"), nonce) @@ -557,7 +596,12 @@ def decrypt_message(self, encrypted_message_with_nonce: bytes, sender_public_key raise ConfigurationError('No private key set to decrypt') if self.crypto_type != KeypairType.ED25519: raise ConfigurationError('Only ed25519 keypair type supported') - private_key = nacl.bindings.crypto_sign_ed25519_sk_to_curve25519(self.private_key + self.public_key) + + with wrap_import(): + import nacl.bindings + import nacl.public + + private_key = nacl.bindings.crypto_sign_ed25519_sk_to_curve25519(self.private_key + self.public_key) # type: ignore[operator] recipient = nacl.public.PrivateKey(private_key) curve25519_public_key = nacl.bindings.crypto_sign_ed25519_pk_to_curve25519(sender_public_key) sender = nacl.public.PublicKey(curve25519_public_key) diff --git a/substrateinterface/storage.py b/substrateinterface/storage.py index 4f585d6..00b7d4d 100644 --- a/substrateinterface/storage.py +++ b/substrateinterface/storage.py @@ -18,8 +18,8 @@ from substrateinterface.exceptions import StorageFunctionNotFound -from scalecodec import ScaleBytes, GenericMetadataVersioned, ss58_decode -from scalecodec.base import ScaleDecoder, RuntimeConfigurationObject, ScaleType +from scalecodec import ScaleBytes, GenericMetadataVersioned, ss58_decode # type: ignore[import-untyped] +from scalecodec.base import ScaleDecoder, RuntimeConfigurationObject, ScaleType # type: ignore[import-untyped] from .utils.hasher import blake2_256, two_x64_concat, xxh128, blake2_128, blake2_128_concat, identity @@ -39,7 +39,7 @@ def __init__( self.pallet = pallet self.storage_function = storage_function self.params = params - self.params_encoded = [] + self.params_encoded = [] # type: ignore[var-annotated] self.data = data self.metadata = metadata self.runtime_config = runtime_config @@ -48,8 +48,8 @@ def __init__( @classmethod def create_from_data(cls, data: bytes, runtime_config: RuntimeConfigurationObject, - metadata: GenericMetadataVersioned, value_scale_type: str = None, pallet: str = None, - storage_function: str = None) -> 'StorageKey': + metadata: GenericMetadataVersioned, value_scale_type: str | None = None, pallet: str | None = None, + storage_function: str | None = None) -> 'StorageKey': """ Create a StorageKey instance providing raw storage key bytes @@ -81,9 +81,9 @@ def create_from_data(cls, data: bytes, runtime_config: RuntimeConfigurationObjec value_scale_type = storage_item.get_value_type_string() return cls( - pallet=None, storage_function=None, params=None, + pallet=None, storage_function=None, params=None, # type: ignore[arg-type] data=data, metadata=metadata, - value_scale_type=value_scale_type, runtime_config=runtime_config + value_scale_type=value_scale_type, runtime_config=runtime_config # type: ignore[arg-type] ) @classmethod @@ -107,7 +107,7 @@ def create_from_storage_function(cls, pallet: str, storage_function: str, params """ storage_key_obj = cls( pallet=pallet, storage_function=storage_function, params=params, - data=None, runtime_config=runtime_config, metadata=metadata, value_scale_type=None + data=None, runtime_config=runtime_config, metadata=metadata, value_scale_type=None # type: ignore[arg-type] ) storage_key_obj.generate() @@ -125,7 +125,7 @@ def convert_storage_parameter(self, scale_type: str, value: Any): return value - def to_hex(self) -> str: + def to_hex(self) -> str: # type: ignore[return] """ Returns a Hex-string representation of current StorageKey data @@ -239,14 +239,14 @@ def decode_scale_value(self, data: Optional[ScaleBytes] = None) -> ScaleType: if data is not None: change_scale_type = self.value_scale_type result_found = True - elif self.metadata_storage_function.value['modifier'] == 'Default': + elif self.metadata_storage_function.value['modifier'] == 'Default': # type: ignore[attr-defined] # Fallback to default value of storage function if no result change_scale_type = self.value_scale_type - data = ScaleBytes(self.metadata_storage_function.value_object['default'].value_object) + data = ScaleBytes(self.metadata_storage_function.value_object['default'].value_object) # type: ignore[attr-defined] else: # No result is interpreted as an Option<...> result change_scale_type = f'Option<{self.value_scale_type}>' - data = ScaleBytes(self.metadata_storage_function.value_object['default'].value_object) + data = ScaleBytes(self.metadata_storage_function.value_object['default'].value_object) # type: ignore[attr-defined] # Decode SCALE result data updated_obj = self.runtime_config.create_scale_object( diff --git a/substrateinterface/utils/__init__.py b/substrateinterface/utils/__init__.py index 87f0a62..1d8de0b 100644 --- a/substrateinterface/utils/__init__.py +++ b/substrateinterface/utils/__init__.py @@ -13,6 +13,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +from contextlib import contextmanager +from typing import Generator import re @@ -32,3 +34,11 @@ def version_tuple(version_string: str) -> tuple: raise ValueError('version_string can only contain numeric characters') return tuple(int(v) for v in version_string.split('.')) + + +@contextmanager +def wrap_import() -> Generator[None, None, None]: + try: + yield + except ModuleNotFoundError as e: + raise ModuleNotFoundError(e.args[0] + ". Install the package with 'full' extra, e.g. `pip install substrate-interface-async[full]`") from e diff --git a/substrateinterface/utils/ecdsa_helpers.py b/substrateinterface/utils/ecdsa_helpers.py index 37c6e85..691af3e 100644 --- a/substrateinterface/utils/ecdsa_helpers.py +++ b/substrateinterface/utils/ecdsa_helpers.py @@ -18,21 +18,21 @@ import hmac import struct -from ecdsa.curves import SECP256k1 -from eth_keys.datatypes import Signature, PrivateKey -from eth_utils import to_checksum_address, keccak as eth_utils_keccak +from substrateinterface.utils import wrap_import BIP39_PBKDF2_ROUNDS = 2048 BIP39_SALT_MODIFIER = "mnemonic" BIP32_PRIVDEV = 0x80000000 -BIP32_CURVE = SECP256k1 BIP32_SEED_MODIFIER = b'Bitcoin seed' ETH_DERIVATION_PATH = "m/44'/60'/0'/0" class PublicKey: def __init__(self, private_key): - self.point = int.from_bytes(private_key, byteorder='big') * BIP32_CURVE.generator + with wrap_import(): + from ecdsa.curves import SECP256k1 # type: ignore[import-untyped] + + self.point = int.from_bytes(private_key, byteorder='big') * SECP256k1.generator def __bytes__(self): xstr = int(self.point.x()).to_bytes(32, byteorder='big') @@ -40,10 +40,13 @@ def __bytes__(self): return (2 + parity).to_bytes(1, byteorder='big') + xstr def address(self): + with wrap_import(): + from eth_utils import to_checksum_address, keccak + x = int(self.point.x()) y = int(self.point.y()) s = x.to_bytes(32, 'big') + y.to_bytes(32, 'big') - return to_checksum_address(eth_utils_keccak(s)[12:]) + return to_checksum_address(keccak(s)[12:]) def mnemonic_to_bip39seed(mnemonic, passphrase): @@ -59,6 +62,9 @@ def bip39seed_to_bip32masternode(seed): def derive_bip32childkey(parent_key, parent_chain_code, i): + with wrap_import(): + from ecdsa.curves import SECP256k1 + assert len(parent_key) == 32 assert len(parent_chain_code) == 32 k = parent_chain_code @@ -72,8 +78,8 @@ def derive_bip32childkey(parent_key, parent_chain_code, i): key, chain_code = h[:32], h[32:] a = int.from_bytes(key, byteorder='big') b = int.from_bytes(parent_key, byteorder='big') - key = (a + b) % int(BIP32_CURVE.order) - if a < BIP32_CURVE.order and key != 0: + key = (a + b) % int(SECP256k1.order) + if a < SECP256k1.order and key != 0: key = key.to_bytes(32, byteorder='big') break d = b'\x01' + h[32:] + struct.pack('>L', i) @@ -92,7 +98,7 @@ def parse_derivation_path(str_derivation_path): return path -def mnemonic_to_ecdsa_private_key(mnemonic: str, str_derivation_path: str = None, passphrase: str = "") -> bytes: +def mnemonic_to_ecdsa_private_key(mnemonic: str, str_derivation_path: str | None = None, passphrase: str = "") -> bytes: if str_derivation_path is None: str_derivation_path = f'{ETH_DERIVATION_PATH}/0' @@ -107,11 +113,17 @@ def mnemonic_to_ecdsa_private_key(mnemonic: str, str_derivation_path: str = None def ecdsa_sign(private_key: bytes, message: bytes) -> bytes: + with wrap_import(): + from eth_keys.datatypes import PrivateKey + signer = PrivateKey(private_key) return signer.sign_msg(message).to_bytes() def ecdsa_verify(signature: bytes, data: bytes, address: bytes) -> bool: + with wrap_import(): + from eth_keys.datatypes import Signature + signature_obj = Signature(signature) recovered_pubkey = signature_obj.recover_public_key_from_msg(data) return recovered_pubkey.to_canonical_address() == address diff --git a/substrateinterface/utils/encrypted_json.py b/substrateinterface/utils/encrypted_json.py index a991176..0784c03 100644 --- a/substrateinterface/utils/encrypted_json.py +++ b/substrateinterface/utils/encrypted_json.py @@ -1,13 +1,11 @@ import base64 -import json from os import urandom from typing import Union -from nacl.hashlib import scrypt -from nacl.secret import SecretBox -from sr25519 import pair_from_ed25519_secret_key +import orjson +from substrateinterface.utils import wrap_import NONCE_LENGTH = 24 SCRYPT_LENGTH = 32 + (3 * 4) @@ -37,42 +35,51 @@ def decode_pair_from_encrypted_json(json_data: Union[str, dict], passphrase: str tuple containing private and public key """ if type(json_data) is str: - json_data = json.loads(json_data) + json_data = orjson.loads(json_data) # Check requirements - if json_data.get('encoding', {}).get('version') != "3": + if json_data.get('encoding', {}).get('version') != "3": # type: ignore[union-attr] raise ValueError("Unsupported JSON format") - encrypted = base64.b64decode(json_data['encoded']) + encrypted = base64.b64decode(json_data['encoded']) # type: ignore[index] + + if 'scrypt' in json_data['encoding']['type']: # type: ignore[index] + with wrap_import(): + import nacl.hashlib - if 'scrypt' in json_data['encoding']['type']: salt = encrypted[0:32] n = int.from_bytes(encrypted[32:36], byteorder='little') p = int.from_bytes(encrypted[36:40], byteorder='little') r = int.from_bytes(encrypted[40:44], byteorder='little') - password = scrypt(passphrase.encode(), salt, n=n, r=r, p=p, dklen=32, maxmem=2 ** 26) + password = nacl.hashlib.scrypt(passphrase.encode(), salt, n=n, r=r, p=p, dklen=32, maxmem=2 ** 26) encrypted = encrypted[SCRYPT_LENGTH:] else: password = passphrase.encode().rjust(32, b'\x00') - if "xsalsa20-poly1305" not in json_data['encoding']['type']: + if "xsalsa20-poly1305" not in json_data['encoding']['type']: # type: ignore[index] raise ValueError("Unsupported encoding type") + with wrap_import(): + import nacl.secret + nonce = encrypted[0:NONCE_LENGTH] message = encrypted[NONCE_LENGTH:] - secret_box = SecretBox(key=password) + secret_box = nacl.secret.SecretBox(key=password) decrypted = secret_box.decrypt(message, nonce) # Decode PKCS8 message secret_key, public_key = decode_pkcs8(decrypted) - if 'sr25519' in json_data['encoding']['content']: + if 'sr25519' in json_data['encoding']['content']: # type: ignore[index] + with wrap_import(): + import sr25519 # type: ignore[import-untyped] + # Secret key from PolkadotJS is an Ed25519 expanded secret key, so has to be converted # https://github.com/polkadot-js/wasm/blob/master/packages/wasm-crypto/src/rs/sr25519.rs#L125 - converted_public_key, secret_key = pair_from_ed25519_secret_key(secret_key) + converted_public_key, secret_key = sr25519.pair_from_ed25519_secret_key(secret_key) assert(public_key == converted_public_key) return secret_key, public_key @@ -120,12 +127,16 @@ def encode_pair(public_key: bytes, private_key: bytes, passphrase: str) -> bytes ------- (Encrypted) PKCS#8 message bytes """ + with wrap_import(): + import nacl.hashlib + import nacl.secret + message = encode_pkcs8(public_key, private_key) salt = urandom(SALT_LENGTH) - password = scrypt(passphrase.encode(), salt, n=SCRYPT_N, r=SCRYPT_R, p=SCRYPT_P, dklen=32, maxmem=2 ** 26) + password = nacl.hashlib.scrypt(passphrase.encode(), salt, n=SCRYPT_N, r=SCRYPT_R, p=SCRYPT_P, dklen=32, maxmem=2 ** 26) - secret_box = SecretBox(key=password) + secret_box = nacl.secret.SecretBox(key=password) message = secret_box.encrypt(message) scrypt_params = SCRYPT_N.to_bytes(4, 'little') + SCRYPT_P.to_bytes(4, 'little') + SCRYPT_R.to_bytes(4, 'little') diff --git a/substrateinterface/utils/hasher.py b/substrateinterface/utils/hasher.py index a39b71d..c57d9b7 100644 --- a/substrateinterface/utils/hasher.py +++ b/substrateinterface/utils/hasher.py @@ -18,9 +18,12 @@ """ from hashlib import blake2b + + import xxhash + def blake2_256(data): """ Helper function to calculate a 32 bytes Blake2b hash for provided data, used as key for Substrate storage items diff --git a/substrateinterface/utils/ss58.py b/substrateinterface/utils/ss58.py index ad95c64..0321da5 100644 --- a/substrateinterface/utils/ss58.py +++ b/substrateinterface/utils/ss58.py @@ -21,8 +21,8 @@ https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58) """ -from scalecodec.utils.ss58 import ss58_decode, ss58_encode, ss58_decode_account_index, ss58_encode_account_index, \ - is_valid_ss58_address, get_ss58_format +from scalecodec.utils.ss58 import ss58_decode, ss58_encode, ss58_decode_account_index # type: ignore[import-untyped] +from scalecodec.utils.ss58 import ss58_encode_account_index, is_valid_ss58_address, get_ss58_format # type: ignore[import-untyped] ss58_decode = ss58_decode diff --git a/test/test_block.py b/test/test_block.py index 7271c6f..d7960b3 100644 --- a/test/test_block.py +++ b/test/test_block.py @@ -15,32 +15,33 @@ # limitations under the License. import unittest -from unittest.mock import MagicMock +from unittest.mock import AsyncMock from test import settings -from scalecodec.exceptions import RemainingScaleBytesNotEmptyException +from scalecodec.exceptions import RemainingScaleBytesNotEmptyException # type: ignore[import-untyped] from substrateinterface import SubstrateInterface from test.fixtures import metadata_node_template_hex -from scalecodec.base import ScaleBytes -from scalecodec.types import Vec, GenericAddress +from scalecodec.base import ScaleBytes # type: ignore[import-untyped] +from scalecodec.types import Vec, GenericAddress # type: ignore[import-untyped] -class BlockTestCase(unittest.TestCase): +class BlockTestCase(unittest.IsolatedAsyncioTestCase): - @classmethod - def setUpClass(cls): - cls.substrate = SubstrateInterface(url='dummy', ss58_format=42, type_registry_preset='substrate-node-template') - metadata_decoder = cls.substrate.runtime_config.create_scale_object( + async def asyncSetUp(self) -> None: + super().setUp() + self.substrate = SubstrateInterface(url='dummy', ss58_format=42, type_registry_preset='substrate-node-template') + self.substrate.reload_type_registry() + metadata_decoder = self.substrate.runtime_config.create_scale_object( 'MetadataVersioned', ScaleBytes(metadata_node_template_hex) ) metadata_decoder.decode() - cls.substrate.get_block_metadata = MagicMock(return_value=metadata_decoder) + self.substrate.get_block_metadata = AsyncMock(return_value=metadata_decoder) # type: ignore[method-assign] - def mocked_query(module, storage_function, block_hash): + async def mocked_query(module, storage_function, block_hash): if module == 'Session' and storage_function == 'Validators': if block_hash == '0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93': vec = Vec() @@ -51,7 +52,7 @@ def mocked_query(module, storage_function, block_hash): raise ValueError(f"Unsupported mocked query {module}.{storage_function} @ {block_hash}") - def mocked_request(method, params, result_handler=None): + async def mocked_request(method, params, result_handler=None): if method in ['chain_getBlockHash', 'chain_getHead', 'chain_getFinalisedHead', 'chain_getFinalizedHead']: return { @@ -136,7 +137,7 @@ def mocked_request(method, params, result_handler=None): elif method == 'state_getStorageAt': return {'jsonrpc': '2.0', 'result': '0x04be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f', 'id': 11} elif method == 'chain_subscribeNewHeads': - return result_handler({ + return await result_handler({ "jsonrpc": "2.0", "params": { "result": { @@ -162,23 +163,57 @@ def mocked_request(method, params, result_handler=None): "result": {'methods': ['account_nextIndex', 'author_hasKey', 'author_hasSessionKeys', 'author_insertKey', 'author_pendingExtrinsics', 'author_removeExtrinsic', 'author_rotateKeys', 'author_submitAndWatchExtrinsic', 'author_submitExtrinsic', 'author_unwatchExtrinsic', 'babe_epochAuthorship', 'chainHead_unstable_body', 'chainHead_unstable_call', 'chainHead_unstable_follow', 'chainHead_unstable_genesisHash', 'chainHead_unstable_header', 'chainHead_unstable_stopBody', 'chainHead_unstable_stopCall', 'chainHead_unstable_stopStorage', 'chainHead_unstable_storage', 'chainHead_unstable_unfollow', 'chainHead_unstable_unpin', 'chainSpec_unstable_chainName', 'chainSpec_unstable_genesisHash', 'chainSpec_unstable_properties', 'chain_getBlock', 'chain_getBlockHash', 'chain_getFinalisedHead', 'chain_getFinalizedHead', 'chain_getHead', 'chain_getHeader', 'chain_getRuntimeVersion', 'chain_subscribeAllHeads', 'chain_subscribeFinalisedHeads', 'chain_subscribeFinalizedHeads', 'chain_subscribeNewHead', 'chain_subscribeNewHeads', 'chain_subscribeRuntimeVersion', 'chain_unsubscribeAllHeads', 'chain_unsubscribeFinalisedHeads', 'chain_unsubscribeFinalizedHeads', 'chain_unsubscribeNewHead', 'chain_unsubscribeNewHeads', 'chain_unsubscribeRuntimeVersion', 'childstate_getKeys', 'childstate_getKeysPaged', 'childstate_getKeysPagedAt', 'childstate_getStorage', 'childstate_getStorageEntries', 'childstate_getStorageHash', 'childstate_getStorageSize', 'dev_getBlockStats', 'grandpa_proveFinality', 'grandpa_roundState', 'grandpa_subscribeJustifications', 'grandpa_unsubscribeJustifications', 'mmr_generateProof', 'mmr_root', 'mmr_verifyProof', 'mmr_verifyProofStateless', 'offchain_localStorageGet', 'offchain_localStorageSet', 'payment_queryFeeDetails', 'payment_queryInfo', 'state_call', 'state_callAt', 'state_getChildReadProof', 'state_getKeys', 'state_getKeysPaged', 'state_getKeysPagedAt', 'state_getMetadata', 'state_getPairs', 'state_getReadProof', 'state_getRuntimeVersion', 'state_getStorage', 'state_getStorageAt', 'state_getStorageHash', 'state_getStorageHashAt', 'state_getStorageSize', 'state_getStorageSizeAt', 'state_queryStorage', 'state_queryStorageAt', 'state_subscribeRuntimeVersion', 'state_subscribeStorage', 'state_traceBlock', 'state_trieMigrationStatus', 'state_unsubscribeRuntimeVersion', 'state_unsubscribeStorage', 'subscribe_newHead', 'sync_state_genSyncSpec', 'system_accountNextIndex', 'system_addLogFilter', 'system_addReservedPeer', 'system_chain', 'system_chainType', 'system_dryRun', 'system_dryRunAt', 'system_health', 'system_localListenAddresses', 'system_localPeerId', 'system_name', 'system_nodeRoles', 'system_peers', 'system_properties', 'system_removeReservedPeer', 'system_reservedPeers', 'system_resetLogFilter', 'system_syncState', 'system_unstable_networkState', 'system_version', 'transaction_unstable_submitAndWatch', 'transaction_unstable_unwatch', 'unsubscribe_newHead']}, "id": 1 } + # FIXME: Random data + elif method == 'system_name': + return { + "jsonrpc": "2.0", + "result": "substrate-node", + "id": 1 + } + elif method == 'system_properties': + return { + "jsonrpc": "2.0", + "result": { + "ss58Format": 42, + "tokenDecimals": 12, + "tokenSymbol": "KSM" + }, + "id": 1 + } + elif method == 'system_chain': + return { + "jsonrpc": "2.0", + "result": "Ethereum", + "id": 1 + } + elif method == 'system_version': + return { + "jsonrpc": "2.0", + "result": "substrate-node", + "id": 1, + } + raise ValueError(f"Unsupported mocked method {method}") - cls.substrate.rpc_request = MagicMock(side_effect=mocked_request) - cls.substrate.query = MagicMock(side_effect=mocked_query) + self.substrate.rpc_request = AsyncMock(side_effect=mocked_request) # type: ignore[method-assign] + self.substrate.query = AsyncMock(side_effect=mocked_query) # type: ignore[method-assign] - cls.babe_substrate = SubstrateInterface( + self.babe_substrate = SubstrateInterface( url=settings.BABE_NODE_URL ) - cls.aura_substrate = SubstrateInterface( + self.aura_substrate = SubstrateInterface( url=settings.AURA_NODE_URL ) + # FIXME: + await self.substrate.init_props() + await self.babe_substrate.init_props() + await self.aura_substrate.init_props() - def test_get_valid_extrinsics(self): + async def test_get_valid_extrinsics(self): - block = self.substrate.get_block( + block = await self.substrate.get_block( block_hash="0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93" ) extrinsics = block['extrinsics'] @@ -187,9 +222,9 @@ def test_get_valid_extrinsics(self): self.assertEqual(extrinsics[0]['call']['call_function'].name, 'set') self.assertEqual(extrinsics[0]['call']['call_args']['now'], 1611744282004) - def test_get_by_block_number(self): + async def test_get_by_block_number(self): - block = self.substrate.get_block( + block = await self.substrate.get_block( block_number=100 ) extrinsics = block['extrinsics'] @@ -198,43 +233,43 @@ def test_get_by_block_number(self): self.assertEqual(extrinsics[0]['call']['call_function'].name, 'set') self.assertEqual(extrinsics[0]['call']['call_args']['now'], 1611744282004) - def test_get_block_by_head(self): + async def test_get_block_by_head(self): - block = self.substrate.get_block() + block = await self.substrate.get_block() self.assertEqual('0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', block['header']['hash']) - def test_get_block_by_finalized_head(self): + async def test_get_block_by_finalized_head(self): - block = self.substrate.get_block(finalized_only=True) + block = await self.substrate.get_block(finalized_only=True) self.assertEqual('0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', block['header']['hash']) - def test_get_block_header(self): + async def test_get_block_header(self): - block = self.substrate.get_block_header( + block = await self.substrate.get_block_header( block_number=100 ) self.assertNotIn('extrinsics', block) - def test_get_block_header_by_head(self): + async def test_get_block_header_by_head(self): - block = self.substrate.get_block_header() + block = await self.substrate.get_block_header() self.assertEqual('0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', block['header']['hash']) - def test_get_block_header_by_finalized_head(self): + async def test_get_block_header_by_finalized_head(self): - block = self.substrate.get_block_header(finalized_only=True) + block = await self.substrate.get_block_header(finalized_only=True) self.assertEqual('0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', block['header']['hash']) - def test_get_extrinsics_decoding_error(self): + async def test_get_extrinsics_decoding_error(self): with self.assertRaises(RemainingScaleBytesNotEmptyException): - self.substrate.get_block( + await self.substrate.get_block( block_hash="0x40b98c29466fa76eeee21008b50d5cb5d7220712ead554eb97a5fd6ba4bc31b5" ) - def test_get_extrinsics_ignore_decoding_error(self): + async def test_get_extrinsics_ignore_decoding_error(self): - block = self.substrate.get_block( + block = await self.substrate.get_block( block_hash="0x40b98c29466fa76eeee21008b50d5cb5d7220712ead554eb97a5fd6ba4bc31b5", ignore_decoding_errors=True ) @@ -246,56 +281,60 @@ def test_get_extrinsics_ignore_decoding_error(self): self.assertEqual(extrinsics[2].value['call']['call_args'][0]['value'], 1611744282004) self.assertEqual(extrinsics[3], None) - def test_include_author(self): + async def test_include_author(self): - block = self.substrate.get_block( + block = await self.substrate.get_block( block_hash="0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93", include_author=False ) self.assertNotIn('author', block) - block = self.substrate.get_block( + block = await self.substrate.get_block( block_hash="0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93", include_author=True ) self.assertIn('author', block) self.assertEqual('5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY', block['author']) - def test_subscribe_block_headers(self): + async def test_subscribe_block_headers(self): - def subscription_handler(obj, update_nr, subscription_id): + async def subscription_handler(obj, update_nr, subscription_id): return f"callback: {obj['header']['number']}" - result = self.substrate.subscribe_block_headers(subscription_handler) - - self.assertEqual(f"callback: 103", result) - - def test_check_requirements(self): - self.assertRaises(ValueError, self.substrate.get_block, - block_hash='0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', - block_number=223 - ) - self.assertRaises(ValueError, self.substrate.get_block, - block_hash='0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', - finalized_only=True - ) - self.assertRaises(ValueError, self.substrate.get_block_header, - block_hash='0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', - block_number=223 - ) - self.assertRaises(ValueError, self.substrate.get_block_header, - block_hash='0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', - finalized_only=True - ) - - def test_block_author_babe(self): - block = self.babe_substrate.get_block(include_author=True) + result = await self.substrate.subscribe_block_headers(subscription_handler) + + self.assertEqual("callback: 103", result) + + async def test_check_requirements(self): + with self.assertRaises(ValueError): + await self.substrate.get_block( + block_hash='0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', + block_number=223, + ) + with self.assertRaises(ValueError): + await self.substrate.get_block( + block_hash='0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', + finalized_only=True, + ) + with self.assertRaises(ValueError): + await self.substrate.get_block_header( + block_hash='0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', + block_number=223, + ) + with self.assertRaises(ValueError): + await self.substrate.get_block_header( + block_hash='0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', + finalized_only=True, + ) + + async def test_block_author_babe(self): + block = await self.babe_substrate.get_block(include_author=True) self.assertIn('author', block) self.assertIsNotNone(block['author']) - def test_block_author_aura(self): - block = self.aura_substrate.get_block(include_author=True) + async def test_block_author_aura(self): + block = await self.aura_substrate.get_block(include_author=True) self.assertIn('author', block) self.assertIsNotNone(block['author']) diff --git a/test/test_contracts.py b/test/test_contracts.py index 432a799..b55efc2 100644 --- a/test/test_contracts.py +++ b/test/test_contracts.py @@ -17,54 +17,55 @@ import os import unittest -from scalecodec import ScaleBytes +from scalecodec import ScaleBytes # type: ignore[import-untyped] from substrateinterface import SubstrateInterface, ContractMetadata, ContractInstance, Keypair, ContractEvent from substrateinterface.exceptions import ContractMetadataParseException from test import settings -class ContractMetadataTestCase(unittest.TestCase): +class ContractMetadataTestCase(unittest.IsolatedAsyncioTestCase): + substrate: SubstrateInterface @classmethod def setUpClass(cls): cls.substrate = SubstrateInterface(url=settings.KUSAMA_NODE_URL) - def setUp(self) -> None: - self.contract_metadata = ContractMetadata.create_from_file( + async def asyncSetUp(self) -> None: + self.contract_metadata = await ContractMetadata.create_from_file( metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'erc20-v0.json'), substrate=self.substrate ) - def test_metadata_parsed(self): + async def test_metadata_parsed(self): self.assertNotEqual(self.contract_metadata.metadata_dict, {}) - def test_incorrect_metadata_file(self): + async def test_incorrect_metadata_file(self): with self.assertRaises(ContractMetadataParseException): - ContractMetadata.create_from_file( + await ContractMetadata.create_from_file( metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'incorrect_metadata.json'), substrate=self.substrate ) - def test_extract_typestring_from_types(self): + async def test_extract_typestring_from_types(self): self.assertEqual('u128', self.contract_metadata.get_type_string_for_metadata_type(1)) self.assertEqual('AccountId', self.contract_metadata.get_type_string_for_metadata_type(5)) self.assertEqual('[u8; 32]', self.contract_metadata.get_type_string_for_metadata_type(6)) self.assertEqual('Option', self.contract_metadata.get_type_string_for_metadata_type(15)) - def test_invalid_type_id(self): + async def test_invalid_type_id(self): with self.assertRaises(ValueError) as cm: self.contract_metadata.get_type_string_for_metadata_type(99) self.assertEqual('type_id 99 not found in metadata', str(cm.exception)) - def test_contract_types_added_type_registry(self): + async def test_contract_types_added_type_registry(self): for type_id in range(1, 16): type_string = self.contract_metadata.get_type_string_for_metadata_type(type_id) if type_string != '()': self.assertIsNotNone(self.substrate.runtime_config.get_decoder_class(type_string)) - def test_return_type_for_message(self): + async def test_return_type_for_message(self): self.assertEqual('u128', self.contract_metadata.get_return_type_string_for_message('total_supply')) self.assertEqual('u128', self.contract_metadata.get_return_type_string_for_message('balance_of')) self.assertEqual( @@ -72,37 +73,37 @@ def test_return_type_for_message(self): self.contract_metadata.get_return_type_string_for_message('approve') ) - def test_invalid_constructor_name(self): + async def test_invalid_constructor_name(self): with self.assertRaises(ValueError) as cm: - self.contract_metadata.generate_constructor_data("invalid") + await self.contract_metadata.generate_constructor_data("invalid") self.assertEqual('Constructor "invalid" not found', str(cm.exception)) - def test_constructor_missing_arg(self): + async def test_constructor_missing_arg(self): with self.assertRaises(ValueError) as cm: - self.contract_metadata.generate_constructor_data("new", args={'test': 2}) + await self.contract_metadata.generate_constructor_data("new", args={'test': 2}) self.assertEqual('Argument "initial_supply" is missing', str(cm.exception)) - def test_constructor_data(self): + async def test_constructor_data(self): - scale_data = self.contract_metadata.generate_constructor_data("new", args={'initial_supply': 1000}) + scale_data = await self.contract_metadata.generate_constructor_data("new", args={'initial_supply': 1000}) self.assertEqual('0xd183512be8030000000000000000000000000000', scale_data.to_hex()) - def test_invalid_message_name(self): + async def test_invalid_message_name(self): with self.assertRaises(ValueError) as cm: - self.contract_metadata.generate_message_data("invalid_msg_name") + await self.contract_metadata.generate_message_data("invalid_msg_name") self.assertEqual('Message "invalid_msg_name" not found', str(cm.exception)) - def test_generate_message_data(self): + async def test_generate_message_data(self): - scale_data = self.contract_metadata.generate_message_data("total_supply") + scale_data = await self.contract_metadata.generate_message_data("total_supply") self.assertEqual('0xdcb736b5', scale_data.to_hex()) - def test_generate_message_data_with_args(self): + async def test_generate_message_data_with_args(self): - scale_data = self.contract_metadata.generate_message_data("transfer", args={ + scale_data = await self.contract_metadata.generate_message_data("transfer", args={ 'to': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', 'value': 10000 }) @@ -111,14 +112,14 @@ def test_generate_message_data_with_args(self): scale_data.to_hex() ) - def test_generate_message_data_missing_arg(self): + async def test_generate_message_data_missing_arg(self): with self.assertRaises(ValueError) as cm: - self.contract_metadata.generate_message_data("transfer", args={ + await self.contract_metadata.generate_message_data("transfer", args={ 'value': 10000 }) self.assertEqual('Argument "to" is missing', str(cm.exception)) - def test_contract_event_decoding(self): + async def test_contract_event_decoding(self): contract_event_data = '0x0001d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d018eaf04151687' + \ '736326c9fea17e25fc5287613693c912909cb226aa4794f26a480000a7dcf75015000000000000000000' @@ -138,33 +139,33 @@ def test_contract_event_decoding(self): ) self.assertEqual(6000000000000000, contract_event_obj.args[2]['value']) - def test_unsupported_ink_env_type_handling(self): + async def test_unsupported_ink_env_type_handling(self): with self.assertRaises(NotImplementedError): - ContractMetadata.create_from_file( + await ContractMetadata.create_from_file( metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'unsupported_type_metadata.json'), substrate=self.substrate ) class ContractMetadataV1TestCase(ContractMetadataTestCase): - def setUp(self) -> None: - self.contract_metadata = ContractMetadata.create_from_file( + async def asyncSetUp(self) -> None: + self.contract_metadata = await ContractMetadata.create_from_file( metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'erc20-v1.json'), substrate=self.substrate ) - def test_metadata_parsed(self): + async def test_metadata_parsed(self): self.assertNotEqual(self.contract_metadata.metadata_dict, {}) - def test_incorrect_metadata_file(self): + async def test_incorrect_metadata_file(self): with self.assertRaises(ContractMetadataParseException): - ContractMetadata.create_from_file( + await ContractMetadata.create_from_file( metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'incorrect_metadata.json'), substrate=self.substrate ) - def test_extract_typestring_from_types(self): + async def test_extract_typestring_from_types(self): self.assertEqual( 'ink::0x418399d957539253bbabc230dffce9e131d9d2e7918edd67e9d7d3f6924e3d9e::1', self.contract_metadata.get_type_string_for_metadata_type(1) @@ -174,20 +175,20 @@ def test_extract_typestring_from_types(self): self.contract_metadata.get_type_string_for_metadata_type(5) ) - def test_invalid_type_id(self): + async def test_invalid_type_id(self): with self.assertRaises(ValueError) as cm: self.contract_metadata.get_type_string_for_metadata_type(99) self.assertEqual('type_id 99 not found in metadata', str(cm.exception)) - def test_contract_types_added_type_registry(self): + async def test_contract_types_added_type_registry(self): for type_id in range(0, len(self.contract_metadata.metadata_dict['types'])): type_string = self.contract_metadata.get_type_string_for_metadata_type(type_id) if type_string != '()': self.assertIsNotNone(self.substrate.runtime_config.get_decoder_class(type_string)) - def test_return_type_for_message(self): + async def test_return_type_for_message(self): self.assertEqual( 'ink::0x418399d957539253bbabc230dffce9e131d9d2e7918edd67e9d7d3f6924e3d9e::0', self.contract_metadata.get_return_type_string_for_message('total_supply') @@ -201,37 +202,37 @@ def test_return_type_for_message(self): self.contract_metadata.get_return_type_string_for_message('approve') ) - def test_invalid_constructor_name(self): + async def test_invalid_constructor_name(self): with self.assertRaises(ValueError) as cm: - self.contract_metadata.generate_constructor_data("invalid") + await self.contract_metadata.generate_constructor_data("invalid") self.assertEqual('Constructor "invalid" not found', str(cm.exception)) - def test_constructor_missing_arg(self): + async def test_constructor_missing_arg(self): with self.assertRaises(ValueError) as cm: - self.contract_metadata.generate_constructor_data("new", args={'test': 2}) + await self.contract_metadata.generate_constructor_data("new", args={'test': 2}) self.assertEqual('Argument "initial_supply" is missing', str(cm.exception)) - def test_constructor_data(self): + async def test_constructor_data(self): - scale_data = self.contract_metadata.generate_constructor_data("new", args={'initial_supply': 1000}) + scale_data = await self.contract_metadata.generate_constructor_data("new", args={'initial_supply': 1000}) self.assertEqual('0x9bae9d5ee8030000000000000000000000000000', scale_data.to_hex()) - def test_invalid_message_name(self): + async def test_invalid_message_name(self): with self.assertRaises(ValueError) as cm: - self.contract_metadata.generate_message_data("invalid_msg_name") + await self.contract_metadata.generate_message_data("invalid_msg_name") self.assertEqual('Message "invalid_msg_name" not found', str(cm.exception)) - def test_generate_message_data(self): + async def test_generate_message_data(self): - scale_data = self.contract_metadata.generate_message_data("total_supply") + scale_data = await self.contract_metadata.generate_message_data("total_supply") self.assertEqual('0xdb6375a8', scale_data.to_hex()) - def test_generate_message_data_with_args(self): + async def test_generate_message_data_with_args(self): - scale_data = self.contract_metadata.generate_message_data("transfer", args={ + scale_data = await self.contract_metadata.generate_message_data("transfer", args={ 'to': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', 'value': 10000 }) @@ -240,14 +241,14 @@ def test_generate_message_data_with_args(self): scale_data.to_hex() ) - def test_generate_message_data_missing_arg(self): + async def test_generate_message_data_missing_arg(self): with self.assertRaises(ValueError) as cm: - self.contract_metadata.generate_message_data("transfer", args={ + await self.contract_metadata.generate_message_data("transfer", args={ 'value': 10000 }) self.assertEqual('Argument "to" is missing', str(cm.exception)) - def test_contract_event_decoding(self): + async def test_contract_event_decoding(self): contract_event_data = '0x0001d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d018eaf04151687' + \ '736326c9fea17e25fc5287613693c912909cb226aa4794f26a480000a7dcf75015000000000000000000' @@ -267,94 +268,96 @@ def test_contract_event_decoding(self): ) self.assertEqual(6000000000000000, contract_event_obj.args[2]['value']) - def test_unsupported_ink_env_type_handling(self): + async def test_unsupported_ink_env_type_handling(self): with self.assertRaises(NotImplementedError): - ContractMetadata.create_from_file( + await ContractMetadata.create_from_file( metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'unsupported_type_metadata.json'), substrate=self.substrate ) class ContractMetadataV3TestCase(ContractMetadataV1TestCase): - def setUp(self) -> None: - self.contract_metadata = ContractMetadata.create_from_file( + async def asyncSetUp(self) -> None: + self.contract_metadata = await ContractMetadata.create_from_file( metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'erc20-v3.json'), substrate=self.substrate ) -class FlipperMetadataV3TestCase(unittest.TestCase): +class FlipperMetadataV3TestCase(unittest.IsolatedAsyncioTestCase): + substrate: SubstrateInterface @classmethod def setUpClass(cls): cls.substrate = SubstrateInterface(url=settings.KUSAMA_NODE_URL) - def setUp(self) -> None: - self.contract_metadata = ContractMetadata.create_from_file( + async def asyncSetUp(self) -> None: + self.contract_metadata = await ContractMetadata.create_from_file( metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'flipper-v3.json'), substrate=self.substrate ) - def test_metadata_parsed(self): + async def test_metadata_parsed(self): self.assertNotEqual(self.contract_metadata.metadata_dict, {}) - def test_incorrect_metadata_file(self): + async def test_incorrect_metadata_file(self): with self.assertRaises(ContractMetadataParseException): - ContractMetadata.create_from_file( + await ContractMetadata.create_from_file( metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'incorrect_metadata.json'), substrate=self.substrate ) - def test_extract_typestring_from_types(self): + async def test_extract_typestring_from_types(self): self.assertEqual( 'ink::0xf051c631190ac47f82e280ba763df932210f6e2447978e24cbe0dcc6d6903c7a::0', self.contract_metadata.get_type_string_for_metadata_type(0) ) - def test_contract_types_added_type_registry(self): + async def test_contract_types_added_type_registry(self): type_string = self.contract_metadata.get_type_string_for_metadata_type(0) if type_string != '()': self.assertIsNotNone(self.substrate.runtime_config.get_decoder_class(type_string)) - def test_return_type_for_message(self): + async def test_return_type_for_message(self): self.assertEqual( 'ink::0xf051c631190ac47f82e280ba763df932210f6e2447978e24cbe0dcc6d6903c7a::0', self.contract_metadata.get_return_type_string_for_message('get') ) self.assertEqual('Null', self.contract_metadata.get_return_type_string_for_message('flip')) - def test_constructor_data(self): + async def test_constructor_data(self): - scale_data = self.contract_metadata.generate_constructor_data("new", args={'init_value': True}) + scale_data = await self.contract_metadata.generate_constructor_data("new", args={'init_value': True}) self.assertEqual('0x9bae9d5e01', scale_data.to_hex()) - def test_generate_message_data(self): + async def test_generate_message_data(self): - scale_data = self.contract_metadata.generate_message_data("get") + scale_data = await self.contract_metadata.generate_message_data("get") self.assertEqual('0x2f865bd9', scale_data.to_hex()) - def test_invalid_constructor_name(self): + async def test_invalid_constructor_name(self): with self.assertRaises(ValueError) as cm: - self.contract_metadata.generate_constructor_data("invalid") + await self.contract_metadata.generate_constructor_data("invalid") self.assertEqual('Constructor "invalid" not found', str(cm.exception)) - def test_invalid_message_name(self): + async def test_invalid_message_name(self): with self.assertRaises(ValueError) as cm: - self.contract_metadata.generate_message_data("invalid_msg_name") + await self.contract_metadata.generate_message_data("invalid_msg_name") self.assertEqual('Message "invalid_msg_name" not found', str(cm.exception)) -class FlipperInstanceTestCase(unittest.TestCase): +class FlipperInstanceTestCase(unittest.IsolatedAsyncioTestCase): + substrate: SubstrateInterface @classmethod def setUpClass(cls): class MockedSubstrateInterface(SubstrateInterface): - def rpc_request(self, method, params, result_handler=None): + async def rpc_request(self, method, params, result_handler=None): if method == 'state_call': return { 'jsonrpc': '2.0', @@ -373,36 +376,37 @@ def rpc_request(self, method, params, result_handler=None): }, 'id': self.request_id} - return super().rpc_request(method, params, result_handler) + return await super().rpc_request(method, params, result_handler) cls.substrate = MockedSubstrateInterface(url=settings.KUSAMA_NODE_URL, type_registry_preset='canvas') # cls.substrate = SubstrateInterface(url='ws://127.0.0.1:9944') cls.keypair = Keypair.create_from_uri('//Alice') - def setUp(self) -> None: - self.contract = ContractInstance.create_from_address( + async def asyncSetUp(self) -> None: + self.contract = await ContractInstance.create_from_address( contract_address="5GhwarrVMH8kjb8XyW6zCfURHbHy3v84afzLbADyYYX6H2Kk", metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'flipper-v3.json'), substrate=self.substrate ) + await self.contract.init() - def test_instance_read(self): + async def test_instance_read(self): - result = self.contract.read(self.keypair, 'get') + result = await self.contract.read(self.keypair, 'get') self.assertEqual(False, result.contract_result_data.value) - def test_instance_read_at_not_best_block(self): - parent_hash = self.substrate.get_block_header()['header']['parentHash'] - result = self.contract.read(self.keypair, 'get', block_hash = parent_hash) + async def test_instance_read_at_not_best_block(self): + parent_hash = (await self.substrate.get_block_header())['header']['parentHash'] + result = await self.contract.read(self.keypair, 'get', block_hash = parent_hash) self.assertEqual(False, result.contract_result_data.value) class FlipperInstanceV4TestCase(FlipperInstanceTestCase): - def setUp(self) -> None: - self.contract = ContractInstance.create_from_address( + async def asyncSetUp(self) -> None: + self.contract = await ContractInstance.create_from_address( contract_address="5DaohteAvvR9PZEhynqWvbFT8HEaHNuiiPTZV61VEUHnqsfU", metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'flipper-v4.json'), substrate=self.substrate @@ -416,7 +420,7 @@ def setUpClass(cls): class MockedSubstrateInterface(SubstrateInterface): - def rpc_request(self, method, params, result_handler=None): + async def rpc_request(self, method, params, result_handler=None): if method == 'state_call': return { 'jsonrpc': '2.0', @@ -435,7 +439,7 @@ def rpc_request(self, method, params, result_handler=None): }, 'id': self.request_id} - return super().rpc_request(method, params, result_handler) + return await super().rpc_request(method, params, result_handler) cls.substrate = MockedSubstrateInterface( url=settings.KUSAMA_NODE_URL, type_registry_preset='canvas', type_registry={'types': {"ContractExecResult": "ContractExecResultTo269"}} @@ -443,22 +447,23 @@ def rpc_request(self, method, params, result_handler=None): cls.keypair = Keypair.create_from_uri('//Alice') - def setUp(self) -> None: - self.contract = ContractInstance.create_from_address( + async def asyncSetUp(self) -> None: + self.contract = await ContractInstance.create_from_address( contract_address="5DaohteAvvR9PZEhynqWvbFT8HEaHNuiiPTZV61VEUHnqsfU", metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'flipper-v5.json'), substrate=self.substrate ) + await self.contract.init() - def test_instance_read(self): + async def test_instance_read(self): - result = self.contract.read(self.keypair, 'get') + result = await self.contract.read(self.keypair, 'get') self.assertEqual({'Ok': False}, result.contract_result_data.value) - def test_instance_read_at_not_best_block(self): - parent_hash = self.substrate.get_block_header()['header']['parentHash'] - result = self.contract.read(self.keypair, 'get', block_hash=parent_hash) + async def test_instance_read_at_not_best_block(self): + parent_hash = (await self.substrate.get_block_header())['header']['parentHash'] + result = await self.contract.read(self.keypair, 'get', block_hash=parent_hash) self.assertEqual({'Ok': False}, result.contract_result_data.value) diff --git a/test/test_create_extrinsics.py b/test/test_create_extrinsics.py index 3630399..7426479 100644 --- a/test/test_create_extrinsics.py +++ b/test/test_create_extrinsics.py @@ -16,14 +16,13 @@ import os import unittest -from scalecodec import ScaleBytes -from scalecodec.type_registry import load_type_registry_file +from scalecodec.type_registry import load_type_registry_file # type: ignore[import-untyped] from substrateinterface import SubstrateInterface, Keypair, ExtrinsicReceipt from substrateinterface.exceptions import SubstrateRequestException from test import settings -class CreateExtrinsicsTestCase(unittest.TestCase): +class CreateExtrinsicsTestCase(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): @@ -48,10 +47,10 @@ def setUpClass(cls): mnemonic = Keypair.generate_mnemonic() cls.keypair = Keypair.create_from_mnemonic(mnemonic) - def test_create_extrinsic_metadata_v14(self): + async def test_create_extrinsic_metadata_v14(self): # Create balance transfer call - call = self.kusama_substrate.compose_call( + call = await self.kusama_substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -60,9 +59,9 @@ def test_create_extrinsic_metadata_v14(self): } ) - extrinsic = self.kusama_substrate.create_signed_extrinsic(call=call, keypair=self.keypair, tip=1) + extrinsic = await self.kusama_substrate.create_signed_extrinsic(call=call, keypair=self.keypair, tip=1) - decoded_extrinsic = self.kusama_substrate.create_scale_object("Extrinsic") + decoded_extrinsic = await self.kusama_substrate.create_scale_object("Extrinsic") decoded_extrinsic.decode(extrinsic.data) self.assertEqual(decoded_extrinsic['call']['call_module'].name, 'Balances') @@ -70,12 +69,12 @@ def test_create_extrinsic_metadata_v14(self): self.assertEqual(extrinsic['nonce'], 0) self.assertEqual(extrinsic['tip'], 1) - def test_create_mortal_extrinsic(self): + async def test_create_mortal_extrinsic(self): for substrate in [self.kusama_substrate, self.polkadot_substrate]: # Create balance transfer call - call = substrate.compose_call( + call = await substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -84,20 +83,20 @@ def test_create_mortal_extrinsic(self): } ) - extrinsic = substrate.create_signed_extrinsic(call=call, keypair=self.keypair, era={'period': 64}) + extrinsic = await substrate.create_signed_extrinsic(call=call, keypair=self.keypair, era={'period': 64}) try: - substrate.submit_extrinsic(extrinsic) + await substrate.submit_extrinsic(extrinsic) self.fail('Should raise no funds to pay fees exception') - except SubstrateRequestException as e: + except SubstrateRequestException: # Extrinsic should be successful if account had balance, eitherwise 'Bad proof' error should be raised pass - def test_create_batch_extrinsic(self): + async def test_create_batch_extrinsic(self): - balance_call = self.polkadot_substrate.compose_call( + balance_call = await self.polkadot_substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -106,7 +105,7 @@ def test_create_batch_extrinsic(self): } ) - call = self.polkadot_substrate.compose_call( + call = await self.polkadot_substrate.compose_call( call_module='Utility', call_function='batch', call_params={ @@ -114,7 +113,7 @@ def test_create_batch_extrinsic(self): } ) - extrinsic = self.polkadot_substrate.create_signed_extrinsic(call=call, keypair=self.keypair, era={'period': 64}) + extrinsic = await self.polkadot_substrate.create_signed_extrinsic(call=call, keypair=self.keypair, era={'period': 64}) # Decode extrinsic again as test extrinsic.decode(extrinsic.data) @@ -122,9 +121,9 @@ def test_create_batch_extrinsic(self): self.assertEqual('Utility', extrinsic.value['call']['call_module']) self.assertEqual('batch', extrinsic.value['call']['call_function']) - def test_create_multisig_extrinsic(self): + async def test_create_multisig_extrinsic(self): - call = self.kusama_substrate.compose_call( + call = await self.kusama_substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -146,7 +145,7 @@ def test_create_multisig_extrinsic(self): threshold=2 ) - extrinsic = self.kusama_substrate.create_multisig_extrinsic(call, self.keypair, multisig_account, era={'period': 64}) + extrinsic = await self.kusama_substrate.create_multisig_extrinsic(call, self.keypair, multisig_account, era={'period': 64}) # Decode extrinsic again as test extrinsic.decode(extrinsic.data) @@ -154,9 +153,9 @@ def test_create_multisig_extrinsic(self): self.assertEqual('Multisig', extrinsic.value['call']['call_module']) self.assertEqual('approve_as_multi', extrinsic.value['call']['call_function']) - def test_create_unsigned_extrinsic(self): + async def test_create_unsigned_extrinsic(self): - call = self.kusama_substrate.compose_call( + call = await self.kusama_substrate.compose_call( call_module='Timestamp', call_function='set', call_params={ @@ -164,13 +163,13 @@ def test_create_unsigned_extrinsic(self): } ) - extrinsic = self.kusama_substrate.create_unsigned_extrinsic(call) + extrinsic = await self.kusama_substrate.create_unsigned_extrinsic(call) self.assertEqual(str(extrinsic.data), '0x280402000ba09cc0317501') - def test_payment_info(self): + async def test_payment_info(self): keypair = Keypair(ss58_address="EaG2CRhJWPb7qmdcJvy3LiWdh26Jreu9Dx6R1rXxPmYXoDk") - call = self.kusama_substrate.compose_call( + call = await self.kusama_substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -178,7 +177,7 @@ def test_payment_info(self): 'value': 2000 } ) - payment_info = self.kusama_substrate.get_payment_info(call=call, keypair=keypair) + payment_info = await self.kusama_substrate.get_payment_info(call=call, keypair=keypair) self.assertIn('class', payment_info) self.assertIn('partialFee', payment_info) @@ -186,9 +185,9 @@ def test_payment_info(self): self.assertGreater(payment_info['partialFee'], 0) - def test_generate_signature_payload_lte_256_bytes(self): + async def test_generate_signature_payload_lte_256_bytes(self): - call = self.kusama_substrate.compose_call( + call = await self.kusama_substrate.compose_call( call_module='System', call_function='remark', call_params={ @@ -196,13 +195,13 @@ def test_generate_signature_payload_lte_256_bytes(self): } ) - signature_payload = self.kusama_substrate.generate_signature_payload(call=call) + signature_payload = await self.kusama_substrate.generate_signature_payload(call=call) self.assertEqual(signature_payload.length, 256) - def test_generate_signature_payload_gt_256_bytes(self): + async def test_generate_signature_payload_gt_256_bytes(self): - call = self.kusama_substrate.compose_call( + call = await self.kusama_substrate.compose_call( call_module='System', call_function='remark', call_params={ @@ -210,13 +209,13 @@ def test_generate_signature_payload_gt_256_bytes(self): } ) - signature_payload = self.kusama_substrate.generate_signature_payload(call=call) + signature_payload = await self.kusama_substrate.generate_signature_payload(call=call) self.assertEqual(signature_payload.length, 32) - def test_create_extrinsic_bytes_signature(self): + async def test_create_extrinsic_bytes_signature(self): # Create balance transfer call - call = self.kusama_substrate.compose_call( + call = await self.kusama_substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -228,24 +227,25 @@ def test_create_extrinsic_bytes_signature(self): signature_hex = '01741d037f6ea0c5269c6d78cde9505178ee928bb1077db49c684f9d1cad430e767e09808bc556ea2962a7b21a' \ 'ada78b3aaf63a8b41e035acfdb0f650634863f83' - extrinsic = self.kusama_substrate.create_signed_extrinsic( + extrinsic = await self.kusama_substrate.create_signed_extrinsic( call=call, keypair=self.keypair, signature=f'0x{signature_hex}' ) self.assertEqual(extrinsic.value['signature']['Sr25519'], f'0x{signature_hex[2:]}') - extrinsic = self.kusama_substrate.create_signed_extrinsic( + extrinsic = await self.kusama_substrate.create_signed_extrinsic( call=call, keypair=self.keypair, signature=bytes.fromhex(signature_hex) ) self.assertEqual(extrinsic.value['signature']['Sr25519'], f'0x{signature_hex[2:]}') - def test_check_extrinsic_receipt(self): + async def test_check_extrinsic_receipt(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0x5bcb59fdfc2ba852dabf31447b84764df85c8f64073757ea800f25b48e63ebd2", block_hash="0x8dae706d0f4882a7db484e708e27d9363a3adfa53baaac8b58c30f7c519a2520" ) + await result.process_events() self.assertTrue(result.is_success) @@ -254,139 +254,159 @@ def test_check_extrinsic_receipt(self): extrinsic_hash="0x43ef739a8e4782e306908e710f333e65843fb35a57ec2a19df21cdc12258fbd8", block_hash="0x8ab60dacd8535d948a755f72a9e09274d17f00693bbbdb55fa898db60a9ce580" ) + await result.process_events() self.assertTrue(result.is_success) - def test_extrinsic_receipt_by_identifier(self): - receipt = self.polkadot_substrate.retrieve_extrinsic_by_identifier("11529741-2") + async def test_extrinsic_receipt_by_identifier(self): + receipt = await self.polkadot_substrate.retrieve_extrinsic_by_identifier("11529741-2") + self.assertEqual(receipt.extrinsic.value['address'], '16amaf1FuEFHstAoKjQiq8ZLWR6zjsYTvAiyHupA8DJ9Mhwu') self.assertEqual( receipt.extrinsic.value['call']['call_args'][0]['value'], '1pg9GBY7Xm5wZSNBr9BrmS978f5g33PGt45PyjiwKpU4hZG' ) - def test_extrinsic_receipt_by_hash(self): - receipt = self.polkadot_substrate.retrieve_extrinsic_by_hash( + async def test_extrinsic_receipt_by_hash(self): + receipt = await self.polkadot_substrate.retrieve_extrinsic_by_hash( block_hash="0x9f726d0ba1e7622c3df8c9f1eacdd1df03deabfc1d788623fc47f494e18c3f38", extrinsic_hash="0xe1ca67a62655d45863be7bf87004a79351bf4a798ba92f666d3a8152bb769d0c" ) + self.assertEqual(receipt.extrinsic.value['address'], '16amaf1FuEFHstAoKjQiq8ZLWR6zjsYTvAiyHupA8DJ9Mhwu') self.assertEqual( receipt.extrinsic.value['call']['call_args'][0]['value'], '1pg9GBY7Xm5wZSNBr9BrmS978f5g33PGt45PyjiwKpU4hZG' ) - def test_check_extrinsic_failed_result(self): + async def test_check_extrinsic_failed_result(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0xa5f2b9f4b8ea9f357780dd49010c99708f580a02624e4500af24b20b92773100", block_hash="0x4b459839cc0b8c807061b5bfc68ca78b2039296174ed0a7754a70b84b287181e" ) + await result.process_events() self.assertFalse(result.is_success) - def test_check_extrinsic_receipt_failed_scaleinfo(self): - receipt = self.kusama_substrate.retrieve_extrinsic_by_identifier("15237367-80") + async def test_check_extrinsic_receipt_failed_scaleinfo(self): + receipt = await self.kusama_substrate.retrieve_extrinsic_by_identifier("15237367-80") + await receipt.process_events() + self.assertFalse(receipt.is_success) - def test_check_extrinsic_failed_error_message(self): + async def test_check_extrinsic_failed_error_message(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0xa5f2b9f4b8ea9f357780dd49010c99708f580a02624e4500af24b20b92773100", block_hash="0x4b459839cc0b8c807061b5bfc68ca78b2039296174ed0a7754a70b84b287181e" ) + await result.process_events() self.assertEqual(result.error_message['name'], 'LiquidityRestrictions') - def test_check_extrinsic_failed_error_message2(self): + async def test_check_extrinsic_failed_error_message2(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0x6147478693eb1ccbe1967e9327c5db093daf5f87bbf6822b4bd8d3dc3bf4e356", block_hash="0x402f22856baf7aaca9510c317b1c392e4d9e6133aabcc0c26f6c5b40dcde70a7" ) + await result.process_events() self.assertEqual(result.error_message['name'], 'MustBeVoter') - def test_check_extrinsic_failed_error_message_portable_registry(self): - receipt = self.kusama_substrate.retrieve_extrinsic_by_identifier("11333518-4") + async def test_check_extrinsic_failed_error_message_portable_registry(self): + receipt = await self.kusama_substrate.retrieve_extrinsic_by_identifier("11333518-4") + await receipt.process_events() self.assertFalse(receipt.is_success) self.assertEqual(881719000, receipt.weight) self.assertEqual(receipt.error_message['name'], 'InsufficientBalance') - def test_check_extrinsic_weight_v2(self): - receipt = self.kusama_substrate.retrieve_extrinsic_by_identifier("14963132-10") + async def test_check_extrinsic_weight_v2(self): + receipt = await self.kusama_substrate.retrieve_extrinsic_by_identifier("14963132-10") + await receipt.process_events() self.assertTrue(receipt.is_success) self.assertEqual({'ref_time': 153773000}, receipt.weight) - def test_check_extrinsic_total_fee_amount(self): + async def test_check_extrinsic_total_fee_amount(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0xa5f2b9f4b8ea9f357780dd49010c99708f580a02624e4500af24b20b92773100", block_hash="0x4b459839cc0b8c807061b5bfc68ca78b2039296174ed0a7754a70b84b287181e" ) + await result.process_events() self.assertEqual(2583332366, result.total_fee_amount) - def test_check_extrinsic_total_fee_amount_portable_registry(self): + async def test_check_extrinsic_total_fee_amount_portable_registry(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0x5937b3fc03ffc62c84d536c3f1949e030b61ca5c680bfd237726e55a75840d1d", block_hash="0x9d693c4fa4d54893bd6b0916843fcb5b7380f43cbea5c462be9213f536fd9a49" ) + await result.process_events() + self.assertTrue(result.is_success) self.assertEqual(161331753, result.total_fee_amount) - def test_check_extrinsic_total_fee_amount2(self): + async def test_check_extrinsic_total_fee_amount2(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0x7347df791b8e47a5eba29c2123783cac638acbe63b4a99024eade4e7805d7ab7", block_hash="0xffbf45b4dfa1be1929b519d5bf6558b2c972ea2e0fe24b623111b238cf67e095" ) + await result.process_events() self.assertEqual(2749998966, result.total_fee_amount) - def test_check_extrinsic_total_fee_amount_new_event(self): - receipt = self.polkadot_substrate.retrieve_extrinsic_by_identifier("12031188-2") + async def test_check_extrinsic_total_fee_amount_new_event(self): + result = await self.polkadot_substrate.retrieve_extrinsic_by_identifier("12031188-2") + await result.process_events() - self.assertEqual(156673273, receipt.total_fee_amount) + self.assertEqual(156673273, result.total_fee_amount) - def test_check_failed_extrinsic_weight(self): + async def test_check_failed_extrinsic_weight(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0xa5f2b9f4b8ea9f357780dd49010c99708f580a02624e4500af24b20b92773100", block_hash="0x4b459839cc0b8c807061b5bfc68ca78b2039296174ed0a7754a70b84b287181e" ) + await result.process_events() self.assertEqual(216625000, result.weight) - def test_check_success_extrinsic_weight(self): + async def test_check_success_extrinsic_weight(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0x5bcb59fdfc2ba852dabf31447b84764df85c8f64073757ea800f25b48e63ebd2", block_hash="0x8dae706d0f4882a7db484e708e27d9363a3adfa53baaac8b58c30f7c519a2520" ) + await result.process_events() self.assertEqual(10000, result.weight) - def test_check_success_extrinsic_weight2(self): + async def test_check_success_extrinsic_weight2(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0x7347df791b8e47a5eba29c2123783cac638acbe63b4a99024eade4e7805d7ab7", block_hash="0xffbf45b4dfa1be1929b519d5bf6558b2c972ea2e0fe24b623111b238cf67e095" ) + await result.process_events() self.assertEqual(252000000, result.weight) - def test_check_success_extrinsic_weight_portable_registry(self): + async def test_check_success_extrinsic_weight_portable_registry(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0x5937b3fc03ffc62c84d536c3f1949e030b61ca5c680bfd237726e55a75840d1d", block_hash="0x9d693c4fa4d54893bd6b0916843fcb5b7380f43cbea5c462be9213f536fd9a49" ) + await result.process_events() + self.assertTrue(result.is_success) self.assertEqual(1234000, result.weight) - def test_extrinsic_result_set_readonly_attr(self): + async def test_extrinsic_result_set_readonly_attr(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, extrinsic_hash="0xa5f2b9f4b8ea9f357780dd49010c99708f580a02624e4500af24b20b92773100" @@ -394,10 +414,10 @@ def test_extrinsic_result_set_readonly_attr(self): with self.assertRaises(AttributeError): result.is_success = False - with self.assertRaises(AttributeError): - result.triggered_events = False + # with self.assertRaises(AttributeError): + # result.triggered_events = False - def test_extrinsic_result_no_blockhash_check_events(self): + async def test_extrinsic_result_no_blockhash_check_events(self): result = ExtrinsicReceipt( substrate=self.kusama_substrate, @@ -405,7 +425,7 @@ def test_extrinsic_result_no_blockhash_check_events(self): ) with self.assertRaises(ValueError) as cm: - result.triggered_events + await result.triggered_events() self.assertEqual('ExtrinsicReceipt can\'t retrieve events because it\'s unknown which block_hash it is ' 'included, manually set block_hash or use `wait_for_inclusion` when sending extrinsic', str(cm.exception)) diff --git a/test/test_extension_interface.py b/test/test_extension_interface.py index 9b08be1..222b804 100644 --- a/test/test_extension_interface.py +++ b/test/test_extension_interface.py @@ -24,7 +24,7 @@ from test import settings -class ExtensionsTestCase(unittest.TestCase): +class ExtensionsTestCase(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): @@ -33,19 +33,19 @@ def setUpClass(cls): ) cls.substrate.register_extension(SubstrateNodeExtension(max_block_range=100)) - def test_search_block_number(self): + async def test_search_block_number(self): block_datetime = datetime(2020, 7, 12, 0, 0, 0, tzinfo=timezone.utc) - block_number = self.substrate.extensions.search_block_number(block_datetime=block_datetime) + block_number = await self.substrate.extensions.search_block_number(block_datetime=block_datetime) self.assertGreaterEqual(block_number, 665270) self.assertLessEqual(block_number, 665280) - def test_search_block_timestamp(self): - block_timestamp = self.substrate.extensions.get_block_timestamp(1000) + async def test_search_block_timestamp(self): + block_timestamp = await self.substrate.extensions.get_block_timestamp(1000) self.assertEqual(1590513426, block_timestamp) - def test_unsupported_extension_call(self): + async def test_unsupported_extension_call(self): with self.assertRaises(ExtensionCallNotFound): self.substrate.extensions.unknown() diff --git a/test/test_helper_functions.py b/test/test_helper_functions.py index dce1807..063e4b7 100644 --- a/test/test_helper_functions.py +++ b/test/test_helper_functions.py @@ -15,17 +15,17 @@ # limitations under the License. import os import unittest -from unittest.mock import MagicMock +from unittest.mock import AsyncMock -from scalecodec import GenericExtrinsic -from scalecodec.type_registry import load_type_registry_file, load_type_registry_preset +from scalecodec import GenericExtrinsic # type: ignore[import-untyped] +from scalecodec.type_registry import load_type_registry_file # type: ignore[import-untyped] from substrateinterface.exceptions import SubstrateRequestException -from scalecodec.base import ScaleBytes +from scalecodec.base import ScaleBytes # type: ignore[import-untyped] from substrateinterface import SubstrateInterface, Keypair from test.settings import POLKADOT_NODE_URL -class TestHelperFunctions(unittest.TestCase): +class TestHelperFunctions(unittest.IsolatedAsyncioTestCase): test_metadata_version = 'V13' @@ -41,7 +41,7 @@ def setUpClass(cls): metadata_decoder = cls.substrate.runtime_config.create_scale_object('MetadataVersioned') metadata_decoder.decode(ScaleBytes(cls.metadata_fixture_dict[cls.test_metadata_version])) - cls.substrate.get_block_metadata = MagicMock(return_value=metadata_decoder) + cls.substrate.get_block_metadata = AsyncMock(return_value=metadata_decoder) def mocked_request(method, params): if method == 'state_getRuntimeVersion': @@ -77,10 +77,38 @@ def mocked_request(method, params): "result": {'methods': ['account_nextIndex', 'author_hasKey', 'author_hasSessionKeys', 'author_insertKey', 'author_pendingExtrinsics', 'author_removeExtrinsic', 'author_rotateKeys', 'author_submitAndWatchExtrinsic', 'author_submitExtrinsic', 'author_unwatchExtrinsic', 'babe_epochAuthorship', 'chainHead_unstable_body', 'chainHead_unstable_call', 'chainHead_unstable_follow', 'chainHead_unstable_genesisHash', 'chainHead_unstable_header', 'chainHead_unstable_stopBody', 'chainHead_unstable_stopCall', 'chainHead_unstable_stopStorage', 'chainHead_unstable_storage', 'chainHead_unstable_unfollow', 'chainHead_unstable_unpin', 'chainSpec_unstable_chainName', 'chainSpec_unstable_genesisHash', 'chainSpec_unstable_properties', 'chain_getBlock', 'chain_getBlockHash', 'chain_getFinalisedHead', 'chain_getFinalizedHead', 'chain_getHead', 'chain_getHeader', 'chain_getRuntimeVersion', 'chain_subscribeAllHeads', 'chain_subscribeFinalisedHeads', 'chain_subscribeFinalizedHeads', 'chain_subscribeNewHead', 'chain_subscribeNewHeads', 'chain_subscribeRuntimeVersion', 'chain_unsubscribeAllHeads', 'chain_unsubscribeFinalisedHeads', 'chain_unsubscribeFinalizedHeads', 'chain_unsubscribeNewHead', 'chain_unsubscribeNewHeads', 'chain_unsubscribeRuntimeVersion', 'childstate_getKeys', 'childstate_getKeysPaged', 'childstate_getKeysPagedAt', 'childstate_getStorage', 'childstate_getStorageEntries', 'childstate_getStorageHash', 'childstate_getStorageSize', 'dev_getBlockStats', 'grandpa_proveFinality', 'grandpa_roundState', 'grandpa_subscribeJustifications', 'grandpa_unsubscribeJustifications', 'mmr_generateProof', 'mmr_root', 'mmr_verifyProof', 'mmr_verifyProofStateless', 'offchain_localStorageGet', 'offchain_localStorageSet', 'payment_queryFeeDetails', 'payment_queryInfo', 'state_call', 'state_callAt', 'state_getChildReadProof', 'state_getKeys', 'state_getKeysPaged', 'state_getKeysPagedAt', 'state_getMetadata', 'state_getPairs', 'state_getReadProof', 'state_getRuntimeVersion', 'state_getStorage', 'state_getStorageAt', 'state_getStorageHash', 'state_getStorageHashAt', 'state_getStorageSize', 'state_getStorageSizeAt', 'state_queryStorage', 'state_queryStorageAt', 'state_subscribeRuntimeVersion', 'state_subscribeStorage', 'state_traceBlock', 'state_trieMigrationStatus', 'state_unsubscribeRuntimeVersion', 'state_unsubscribeStorage', 'subscribe_newHead', 'sync_state_genSyncSpec', 'system_accountNextIndex', 'system_addLogFilter', 'system_addReservedPeer', 'system_chain', 'system_chainType', 'system_dryRun', 'system_dryRunAt', 'system_health', 'system_localListenAddresses', 'system_localPeerId', 'system_name', 'system_nodeRoles', 'system_peers', 'system_properties', 'system_removeReservedPeer', 'system_reservedPeers', 'system_resetLogFilter', 'system_syncState', 'system_unstable_networkState', 'system_version', 'transaction_unstable_submitAndWatch', 'transaction_unstable_unwatch', 'unsubscribe_newHead']}, "id": 1 } - + # FIXME: Random data + elif method == 'system_name': + return { + "jsonrpc": "2.0", + "result": "substrate-node", + "id": 1 + } + elif method == 'system_properties': + return { + "jsonrpc": "2.0", + "result": { + "ss58Format": 42, + "tokenDecimals": 12, + "tokenSymbol": "KSM" + }, + "id": 1 + } + elif method == 'system_chain': + return { + "jsonrpc": "2.0", + "result": "Ethereum", + "id": 1 + } + elif method == 'system_version': + return { + "jsonrpc": "2.0", + "result": "substrate-node", + "id": 1, + } raise NotImplementedError(method) - cls.substrate.rpc_request = MagicMock(side_effect=mocked_request) + cls.substrate.rpc_request = AsyncMock(side_effect=mocked_request) cls.empty_substrate = SubstrateInterface(url='dummy', ss58_format=42, type_registry_preset='kusama') @@ -88,7 +116,7 @@ def mocked_request(method, params): return {'jsonrpc': '2.0', 'result': None, 'id': 1} - cls.empty_substrate.rpc_request = MagicMock(side_effect=mocked_request) + cls.empty_substrate.rpc_request = AsyncMock(side_effect=mocked_request) cls.error_substrate = SubstrateInterface(url='wss://kusama-rpc.polkadot.io', ss58_format=2, type_registry_preset='kusama') @@ -97,116 +125,122 @@ def mocked_request(method, params): # 'code': -32602, 'message': 'Generic error message' # }, 'id': 1} # - # cls.error_substrate.rpc_request = MagicMock(side_effect=mocked_request) + # cls.error_substrate.rpc_request = AsyncMock(side_effect=mocked_request) - def test_decode_scale(self): - self.assertEqual(self.substrate.decode_scale('Compact', '0x08'), 2) + async def test_decode_scale(self): + self.assertEqual(await self.substrate.decode_scale('Compact', '0x08'), 2) - def test_encode_scale(self): - self.assertEqual(self.substrate.encode_scale('Compact', 3), ScaleBytes('0x0c')) + async def test_encode_scale(self): + self.assertEqual(await self.substrate.encode_scale('Compact', 3), ScaleBytes('0x0c')) - def test_create_scale_object(self): - scale_obj = self.substrate.create_scale_object("Bytes") + async def test_create_scale_object(self): + scale_obj = await self.substrate.create_scale_object("Bytes") self.assertEqual(scale_obj.encode("Test"), ScaleBytes("0x1054657374")) self.assertEqual(scale_obj.decode(ScaleBytes("0x1054657374")), "Test") - def test_get_type_definition(self): - info = self.substrate.get_type_definition('MultiSignature') + async def test_get_type_definition(self): + info = await self.substrate.get_type_definition('MultiSignature') self.assertDictEqual({'Ed25519': 'h512', 'Sr25519': 'h512', 'Ecdsa': '[u8; 65]'}, info) - info = self.substrate.get_type_definition('Balance') + info = await self.substrate.get_type_definition('Balance') self.assertEqual('u128', info) - def test_get_metadata(self): - metadata = self.substrate.get_metadata() + async def test_get_metadata(self): + metadata = await self.substrate.get_metadata() self.assertIsNotNone(metadata) self.assertEqual(metadata.__class__.__name__, 'MetadataVersioned') - def test_get_metadata_modules(self): - for module in self.substrate.get_metadata_modules(): + async def test_get_metadata_modules(self): + for module in await self.substrate.get_metadata_modules(): self.assertIn('module_id', module) self.assertIn('name', module) self.assertEqual(module['spec_version'], 2023) - def test_get_metadata_call_function(self): - call_function = self.substrate.get_metadata_call_function("Balances", "transfer") + async def test_get_metadata_call_function(self): + call_function = await self.substrate.get_metadata_call_function("Balances", "transfer") self.assertEqual("transfer", call_function.name) self.assertEqual('dest', call_function.args[0].name) self.assertEqual('value', call_function.args[1].name) - def test_get_metadata_call_functions(self): - call_functions = self.substrate.get_metadata_call_functions() + async def test_get_metadata_call_functions(self): + call_functions = await self.substrate.get_metadata_call_functions() self.assertGreater(len(call_functions), 0) - def test_get_metadata_event(self): - event = self.substrate.get_metadata_event("Balances", "Transfer") + async def test_get_metadata_event(self): + event = await self.substrate.get_metadata_event("Balances", "Transfer") self.assertEqual("Transfer", event.name) self.assertEqual('AccountId', event.args[0].type) self.assertEqual('AccountId', event.args[1].type) self.assertEqual('Balance', event.args[2].type) - def test_get_metadata_constant(self): - constant = self.substrate.get_metadata_constant("System", "BlockHashCount") + async def test_get_metadata_constant(self): + constant = await self.substrate.get_metadata_constant("System", "BlockHashCount") self.assertEqual("BlockHashCount", constant.name) self.assertEqual("BlockNumber", constant.type) self.assertEqual("0x60090000", f"0x{constant.constant_value.hex()}") - def test_get_metadata_constants(self): - constants = self.substrate.get_metadata_constants() + async def test_get_metadata_constants(self): + constants = await self.substrate.get_metadata_constants() self.assertGreater(len(constants), 0) - def test_get_constant(self): - constant = self.substrate.get_constant("System", "BlockHashCount") + async def test_get_constant(self): + constant = await self.substrate.get_constant("System", "BlockHashCount") self.assertEqual(2400, constant.value) - constant = self.substrate.get_constant("Balances", "ExistentialDeposit") + constant = await self.substrate.get_constant("Balances", "ExistentialDeposit") self.assertEqual(100000000000000, constant.value) # Also test cache method doesn't mix up results - constant = self.substrate.get_constant("System", "BlockHashCount") + constant = await self.substrate.get_constant("System", "BlockHashCount") self.assertEqual(2400, constant.value) - def test_get_metadata_storage_function(self): - storage = self.substrate.get_metadata_storage_function("System", "Account") + async def test_get_metadata_storage_function(self): + storage = await self.substrate.get_metadata_storage_function("System", "Account") self.assertEqual("Account", storage.name) self.assertEqual("AccountId", storage.get_params_type_string()[0]) self.assertEqual("Blake2_128Concat", storage.type['Map']['hasher']) - def test_get_metadata_storage_functions(self): - storages = self.substrate.get_metadata_storage_functions() + async def test_get_metadata_storage_functions(self): + storages = await self.substrate.get_metadata_storage_functions() self.assertGreater(len(storages), 0) - def test_get_metadata_error(self): - error = self.substrate.get_metadata_error("System", "InvalidSpecName") + async def test_get_metadata_error(self): + error = await self.substrate.get_metadata_error("System", "InvalidSpecName") self.assertEqual("InvalidSpecName", error.name) self.assertIsNotNone(error.docs) - def test_get_metadata_errors(self): - errors = self.substrate.get_metadata_errors() + async def test_get_metadata_errors(self): + errors = await self.substrate.get_metadata_errors() self.assertGreater(len(errors), 0) - def test_helper_functions_should_return_null_not_exists(self): - self.assertIsNone(self.empty_substrate.get_block_number( + async def test_helper_functions_should_return_null_not_exists(self): + self.assertIsNone(await self.empty_substrate.get_block_number( block_hash="0x6666666666666666666666666666666666666666666666666666666666666666" )) - self.assertIsNone(self.empty_substrate.get_block_hash(block_id=99999999999999999)) - self.assertIsNone(self.empty_substrate.get_block_header(block_hash='0x')) - self.assertIsNone(self.empty_substrate.get_block_metadata(block_hash='0x')['result']) - self.assertIsNone(self.empty_substrate.get_block_runtime_version(block_hash='0x')) - - def test_helper_functions_invalid_input(self): - self.assertRaises(SubstrateRequestException, self.error_substrate.get_block_number, "0x6666666666666666") - self.assertRaises(SubstrateRequestException, self.error_substrate.get_block_hash, -1) - self.assertRaises(SubstrateRequestException, self.error_substrate.get_block_header, '0x') - self.assertRaises(SubstrateRequestException, self.error_substrate.get_block_metadata, '0x') - self.assertRaises(SubstrateRequestException, self.error_substrate.get_block_runtime_version, '0x') - self.assertRaises(ValueError, self.error_substrate.query, 'System', 'Account', ['0x']) - - def test_storage_function_param_info(self): - storage_function = self.substrate.get_metadata_storage_function("System", "Account") + self.assertIsNone(await self.empty_substrate.get_block_hash(block_id=99999999999999999)) + self.assertIsNone(await self.empty_substrate.get_block_header(block_hash='0x')) + self.assertIsNone((await self.empty_substrate.get_block_metadata(block_hash='0x'))['result']) + self.assertIsNone(await self.empty_substrate.get_block_runtime_version(block_hash='0x')) + + async def test_helper_functions_invalid_input(self): + with self.assertRaises(SubstrateRequestException): + await self.error_substrate.get_block_number("0x6666666666666666") + with self.assertRaises(SubstrateRequestException): + await self.error_substrate.get_block_hash(-1) + with self.assertRaises(SubstrateRequestException): + await self.error_substrate.get_block_header('0x') + with self.assertRaises(SubstrateRequestException): + await self.error_substrate.get_block_metadata('0x') + with self.assertRaises(SubstrateRequestException): + await self.error_substrate.get_block_runtime_version('0x') + with self.assertRaises(ValueError): + await self.error_substrate.query('System', 'Account', ['0x']) + + async def test_storage_function_param_info(self): + storage_function = await self.substrate.get_metadata_storage_function("System", "Account") with self.assertRaises(NotImplementedError): storage_function.get_param_info() @@ -214,27 +248,27 @@ def test_storage_function_param_info(self): class TestHelperFunctionsV14(TestHelperFunctions): test_metadata_version = 'V14' - def test_get_metadata_constant(self): - constant = self.substrate.get_metadata_constant("System", "BlockHashCount") + async def test_get_metadata_constant(self): + constant = await self.substrate.get_metadata_constant("System", "BlockHashCount") self.assertEqual("BlockHashCount", constant.name) self.assertEqual("scale_info::4", constant.type) self.assertEqual("0x60090000", f"0x{constant.constant_value.hex()}") - def test_get_metadata_storage_function(self): - storage = self.substrate.get_metadata_storage_function("System", "Account") + async def test_get_metadata_storage_function(self): + storage = await self.substrate.get_metadata_storage_function("System", "Account") self.assertEqual("Account", storage.name) self.assertEqual("scale_info::0", storage.get_params_type_string()[0]) self.assertEqual("Blake2_128Concat", storage.type['Map']['hashers'][0]) - def test_get_metadata_event(self): - event = self.substrate.get_metadata_event("Balances", "Transfer") + async def test_get_metadata_event(self): + event = await self.substrate.get_metadata_event("Balances", "Transfer") self.assertEqual("Transfer", event.name) self.assertEqual('scale_info::0', event.args[0].type) self.assertEqual('scale_info::0', event.args[1].type) self.assertEqual('scale_info::6', event.args[2].type) - def test_storage_function_param_info(self): - storage_function = self.substrate.get_metadata_storage_function("System", "Account") + async def test_storage_function_param_info(self): + storage_function = await self.substrate.get_metadata_storage_function("System", "Account") info = storage_function.get_param_info() self.assertEqual(1, len(info)) self.assertEqual('AccountId', info[0]) @@ -243,52 +277,53 @@ def test_storage_function_param_info(self): class TestHelperFunctionsKarura(TestHelperFunctionsV14): test_metadata_version = 'karura_test' - def test_storage_function_param_info(self): - storage_function = self.substrate.get_metadata_storage_function("Tokens", "TotalIssuance") + async def test_storage_function_param_info(self): + storage_function = await self.substrate.get_metadata_storage_function("Tokens", "TotalIssuance") info = storage_function.get_param_info() self.assertEqual(1, len(info)) self.assertEqual('ACA', info[0]['Token'][0]) - storage_function = self.substrate.get_metadata_storage_function("Rewards", "PoolInfos") + storage_function = await self.substrate.get_metadata_storage_function("Rewards", "PoolInfos") info = storage_function.get_param_info() self.assertEqual(1, len(info)) self.assertEqual('ACA', info[0]['Loans']['Token'][0]) - storage_function = self.substrate.get_metadata_storage_function("Dex", "TradingPairStatuses") + storage_function = await self.substrate.get_metadata_storage_function("Dex", "TradingPairStatuses") info = storage_function.get_param_info() self.assertEqual(1, len(info)) self.assertEqual(2, len(info[0])) self.assertEqual('ACA', info[0][0]['Token'][0]) - def test_get_metadata_constant(self): - constant = self.substrate.get_metadata_constant("System", "BlockHashCount") + async def test_get_metadata_constant(self): + constant = await self.substrate.get_metadata_constant("System", "BlockHashCount") self.assertEqual("BlockHashCount", constant.name) self.assertEqual("scale_info::4", constant.type) self.assertEqual("0xb0040000", f"0x{constant.constant_value.hex()}") - def test_get_constant(self): - constant = self.substrate.get_constant("System", "BlockHashCount") + async def test_get_constant(self): + constant = await self.substrate.get_constant("System", "BlockHashCount") self.assertEqual(1200, constant.value) - constant = self.substrate.get_constant("Balances", "ExistentialDeposit") + constant = await self.substrate.get_constant("Balances", "ExistentialDeposit") self.assertEqual(100000000000, constant.value) # Also test cache method doesn't mix up results - constant = self.substrate.get_constant("System", "BlockHashCount") + constant = await self.substrate.get_constant("System", "BlockHashCount") self.assertEqual(1200, constant.value) -class TestRPCHelperFunctions(unittest.TestCase): +class TestRPCHelperFunctions(unittest.IsolatedAsyncioTestCase): + substrate: SubstrateInterface @classmethod def setUpClass(cls) -> None: cls.substrate = SubstrateInterface(url=POLKADOT_NODE_URL) - cls.substrate.orig_rpc_request = cls.substrate.rpc_request + orig_rpc_request = cls.substrate.rpc_request - def mocked_request(method, params): + async def mocked_request(method, params): if method == 'author_pendingExtrinsics': return { 'jsonrpc': '2.0', 'result': [ @@ -297,18 +332,20 @@ def mocked_request(method, params): 'id': 17 } - return cls.substrate.orig_rpc_request(method, params) + return await orig_rpc_request(method, params) - cls.substrate.rpc_request = MagicMock(side_effect=mocked_request) + cls.substrate.rpc_request = AsyncMock(side_effect=mocked_request) # type: ignore[method-assign] - def test_pending_extrinsics(self): - pending_extrinsics = self.substrate.retrieve_pending_extrinsics() + async def test_pending_extrinsics(self): + pending_extrinsics = await self.substrate.retrieve_pending_extrinsics() self.assertEqual(len(pending_extrinsics), 1) self.assertIsInstance(pending_extrinsics[0], GenericExtrinsic) -class SS58HelperTestCase(unittest.TestCase): +class SS58HelperTestCase(unittest.IsolatedAsyncioTestCase): + keypair: Keypair + substrate: SubstrateInterface @classmethod def setUpClass(cls) -> None: @@ -316,13 +353,16 @@ def setUpClass(cls) -> None: cls.substrate = SubstrateInterface(url=POLKADOT_NODE_URL) - def test_ss58_decode(self): + async def test_ss58_decode(self): + await self.substrate.init_props() public_key = self.substrate.ss58_decode("15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5") self.assertEqual("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", public_key) - def test_ss58_encode(self): + async def test_ss58_encode(self): + await self.substrate.init_props() + ss58_address = self.substrate.ss58_encode("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d") self.assertEqual("15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5", ss58_address) @@ -334,7 +374,7 @@ def test_ss58_encode(self): ) self.assertEqual("15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5", ss58_address) - def test_ss58_encode_custom_format(self): + async def test_ss58_encode_custom_format(self): ss58_address = self.substrate.ss58_encode( "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", ss58_format=2 ) diff --git a/test/test_init.py b/test/test_init.py index 4a181df..651a696 100644 --- a/test/test_init.py +++ b/test/test_init.py @@ -16,24 +16,28 @@ import unittest -from scalecodec import ScaleBytes -from scalecodec.exceptions import RemainingScaleBytesNotEmptyException +from scalecodec import ScaleBytes # type: ignore[import-untyped] +from scalecodec.exceptions import RemainingScaleBytesNotEmptyException # type: ignore[import-untyped] from substrateinterface import SubstrateInterface from test import settings -class TestInit(unittest.TestCase): +class TestInit(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): cls.kusama_substrate = SubstrateInterface(url=settings.KUSAMA_NODE_URL) cls.polkadot_substrate = SubstrateInterface(url=settings.POLKADOT_NODE_URL) - def test_chain(self): + async def asyncSetUp(self): + await self.kusama_substrate.init_props() + await self.polkadot_substrate.init_props() + + async def test_chain(self): self.assertEqual('Kusama', self.kusama_substrate.chain) self.assertEqual('Polkadot', self.polkadot_substrate.chain) - def test_properties(self): + async def test_properties(self): self.assertDictEqual( {'ss58Format': 2, 'tokenDecimals': 12, 'tokenSymbol': 'KSM'}, self.kusama_substrate.properties ) @@ -41,38 +45,38 @@ def test_properties(self): {'ss58Format': 0, 'tokenDecimals': 10, 'tokenSymbol': 'DOT'}, self.polkadot_substrate.properties ) - def test_ss58_format(self): + async def test_ss58_format(self): self.assertEqual(2, self.kusama_substrate.ss58_format) self.assertEqual(0, self.polkadot_substrate.ss58_format) - def test_token_symbol(self): + async def test_token_symbol(self): self.assertEqual('KSM', self.kusama_substrate.token_symbol) self.assertEqual('DOT', self.polkadot_substrate.token_symbol) - def test_token_decimals(self): + async def test_token_decimals(self): self.assertEqual(12, self.kusama_substrate.token_decimals) self.assertEqual(10, self.polkadot_substrate.token_decimals) - def test_override_ss58_format_init(self): + async def test_override_ss58_format_init(self): substrate = SubstrateInterface(url=settings.KUSAMA_NODE_URL, ss58_format=99) self.assertEqual(99, substrate.ss58_format) - def test_override_incorrect_ss58_format(self): + async def test_override_incorrect_ss58_format(self): substrate = SubstrateInterface(url=settings.KUSAMA_NODE_URL) with self.assertRaises(TypeError): substrate.ss58_format = 'test' - def test_override_token_symbol(self): + async def test_override_token_symbol(self): substrate = SubstrateInterface(url=settings.KUSAMA_NODE_URL) substrate.token_symbol = 'TST' self.assertEqual('TST', substrate.token_symbol) - def test_override_incorrect_token_decimals(self): + async def test_override_incorrect_token_decimals(self): substrate = SubstrateInterface(url=settings.KUSAMA_NODE_URL) with self.assertRaises(TypeError): substrate.token_decimals = 'test' - def test_is_valid_ss58_address(self): + async def test_is_valid_ss58_address(self): self.assertTrue(self.kusama_substrate.is_valid_ss58_address('GLdQ4D4wkeEJUX8DBT9HkpycFVYQZ3fmJyQ5ZgBRxZ4LD3S')) self.assertFalse( self.kusama_substrate.is_valid_ss58_address('12gX42C4Fj1wgtfgoP624zeHrcPBqzhb4yAENyvFdGX6EUnN') @@ -86,28 +90,28 @@ def test_is_valid_ss58_address(self): self.polkadot_substrate.is_valid_ss58_address('12gX42C4Fj1wgtfgoP624zeHrcPBqzhb4yAENyvFdGX6EUnN') ) - def test_lru_cache_not_shared(self): - block_number = self.kusama_substrate.get_block_number("0xa4d873095aeae6fc1f3953f0a0085ee216bf8629342aaa92bd53f841e1052e1c") - block_number2 = self.polkadot_substrate.get_block_number( + async def test_lru_cache_not_shared(self): + block_number = await self.kusama_substrate.get_block_number("0xa4d873095aeae6fc1f3953f0a0085ee216bf8629342aaa92bd53f841e1052e1c") + block_number2 = await self.polkadot_substrate.get_block_number( "0xa4d873095aeae6fc1f3953f0a0085ee216bf8629342aaa92bd53f841e1052e1c") self.assertIsNotNone(block_number) self.assertIsNone(block_number2) - def test_context_manager(self): - with SubstrateInterface(url=settings.KUSAMA_NODE_URL) as substrate: + async def test_context_manager(self): + async with SubstrateInterface(url=settings.KUSAMA_NODE_URL) as substrate: self.assertTrue(substrate.websocket.connected) self.assertEqual(2, substrate.ss58_format) self.assertFalse(substrate.websocket.connected) - def test_strict_scale_decode(self): + async def test_strict_scale_decode(self): with self.assertRaises(RemainingScaleBytesNotEmptyException): - self.kusama_substrate.decode_scale('u8', ScaleBytes('0x0101')) + await self.kusama_substrate.decode_scale('u8', ScaleBytes('0x0101')) - with SubstrateInterface(url=settings.KUSAMA_NODE_URL, config={'strict_scale_decode': False}) as substrate: - result = substrate.decode_scale('u8', ScaleBytes('0x0101')) + async with SubstrateInterface(url=settings.KUSAMA_NODE_URL, config={'strict_scale_decode': False}) as substrate: + result = await substrate.decode_scale('u8', ScaleBytes('0x0101')) self.assertEqual(result, 1) diff --git a/test/test_keypair.py b/test/test_keypair.py index 28ce4f8..d1c6005 100644 --- a/test/test_keypair.py +++ b/test/test_keypair.py @@ -19,21 +19,21 @@ from substrateinterface.constants import DEV_PHRASE from substrateinterface.key import extract_derive_path from substrateinterface.exceptions import ConfigurationError -from scalecodec.base import ScaleBytes +from scalecodec.base import ScaleBytes # type: ignore[import-untyped] from substrateinterface import Keypair, KeypairType, MnemonicLanguageCode -class KeyPairTestCase(unittest.TestCase): +class KeyPairTestCase(unittest.IsolatedAsyncioTestCase): - def test_generate_mnemonic(self): + async def test_generate_mnemonic(self): mnemonic = Keypair.generate_mnemonic() self.assertTrue(Keypair.validate_mnemonic(mnemonic)) - def test_valid_mnemonic(self): + async def test_valid_mnemonic(self): mnemonic = "old leopard transfer rib spatial phone calm indicate online fire caution review" self.assertTrue(Keypair.validate_mnemonic(mnemonic)) - def test_valid_mnemonic_multi_lang(self): + async def test_valid_mnemonic_multi_lang(self): mnemonic = "秘 心 姜 封 迈 走 描 朗 出 莫 人 口" self.assertTrue(Keypair.validate_mnemonic(mnemonic, MnemonicLanguageCode.CHINESE_SIMPLIFIED)) @@ -43,7 +43,7 @@ def test_valid_mnemonic_multi_lang(self): keypair = Keypair.create_from_mnemonic(mnemonic, language_code=MnemonicLanguageCode.FRENCH) self.assertEqual("5FUQmUcb3KAR9rBJekCVcNX1DyPV3n7ZyLfkxohjpbL3xkxR", keypair.ss58_address) - def test_create_mnemonic_multi_lang(self): + async def test_create_mnemonic_multi_lang(self): mnemonic_path = "秘 心 姜 封 迈 走 描 朗 出 莫 人 口//0" keypair = Keypair.create_from_uri(mnemonic_path, language_code=MnemonicLanguageCode.CHINESE_SIMPLIFIED) self.assertNotEqual(keypair, None) @@ -54,22 +54,22 @@ def test_create_mnemonic_multi_lang(self): self.assertNotEqual(keypair, None) self.assertEqual("5FUQmUcb3KAR9rBJekCVcNX1DyPV3n7ZyLfkxohjpbL3xkxR", keypair.ss58_address) - def test_invalid_mnemonic(self): + async def test_invalid_mnemonic(self): mnemonic = "This is an invalid mnemonic" self.assertFalse(Keypair.validate_mnemonic(mnemonic)) - def test_create_sr25519_keypair(self): + async def test_create_sr25519_keypair(self): mnemonic = "old leopard transfer rib spatial phone calm indicate online fire caution review" keypair = Keypair.create_from_mnemonic(mnemonic, ss58_format=0) self.assertEqual(keypair.ss58_address, "16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2") - def test_only_provide_ss58_address(self): + async def test_only_provide_ss58_address(self): keypair = Keypair(ss58_address='16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2') self.assertEqual(keypair.public_key, bytes.fromhex('e4359ad3e2716c539a1d663ebd0a51bdc5c98a12e663bb4c4402db47828c9446')) - def test_only_provide_public_key(self): + async def test_only_provide_public_key(self): keypair = Keypair( public_key=bytes.fromhex('e4359ad3e2716c539a1d663ebd0a51bdc5c98a12e663bb4c4402db47828c9446'), @@ -77,36 +77,36 @@ def test_only_provide_public_key(self): ) self.assertEqual(keypair.ss58_address, '16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2') - def test_provide_no_ss58_address_and_public_key(self): + async def test_provide_no_ss58_address_and_public_key(self): self.assertRaises(ValueError, Keypair) - def test_incorrect_private_key_length_sr25519(self): + async def test_incorrect_private_key_length_sr25519(self): self.assertRaises( ValueError, Keypair, private_key='0x23', ss58_address='16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2' ) - def test_incorrect_public_key(self): + async def test_incorrect_public_key(self): self.assertRaises(ValueError, Keypair, public_key='0x23') - def test_sign_and_verify(self): + async def test_sign_and_verify(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic) signature = keypair.sign("Test123") self.assertTrue(keypair.verify("Test123", signature)) - def test_sign_and_verify_multi_lang(self): + async def test_sign_and_verify_multi_lang(self): mnemonic = Keypair.generate_mnemonic(language_code=MnemonicLanguageCode.FRENCH) keypair = Keypair.create_from_mnemonic(mnemonic, language_code=MnemonicLanguageCode.FRENCH) signature = keypair.sign("Test123") self.assertTrue(keypair.verify("Test123", signature)) - def test_sign_and_verify_hex_data(self): + async def test_sign_and_verify_hex_data(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic) signature = keypair.sign("0x1234") self.assertTrue(keypair.verify("0x1234", signature)) - def test_sign_and_verify_scale_bytes(self): + async def test_sign_and_verify_scale_bytes(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic) @@ -115,18 +115,18 @@ def test_sign_and_verify_scale_bytes(self): signature = keypair.sign(data) self.assertTrue(keypair.verify(data, signature)) - def test_sign_and_verify_wrapping(self): + async def test_sign_and_verify_wrapping(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic) signature = keypair.sign('test') self.assertTrue(keypair.verify('test', signature)) - def test_sign_missing_private_key(self): + async def test_sign_missing_private_key(self): keypair = Keypair(ss58_address="5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") self.assertRaises(ConfigurationError, keypair.sign, "0x1234") - def test_sign_unsupported_crypto_type(self): + async def test_sign_unsupported_crypto_type(self): keypair = Keypair.create_from_private_key( ss58_address='16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2', private_key='0x1f1995bdf3a17b60626a26cfe6f564b337d46056b7a1281b64c649d592ccda0a9cffd34d9fb01cae1fba61aeed184c817442a2186d5172416729a4b54dd4b84e', @@ -134,7 +134,7 @@ def test_sign_unsupported_crypto_type(self): ) self.assertRaises(ConfigurationError, keypair.sign, "0x1234") - def test_verify_unsupported_crypto_type(self): + async def test_verify_unsupported_crypto_type(self): keypair = Keypair.create_from_private_key( ss58_address='16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2', private_key='0x1f1995bdf3a17b60626a26cfe6f564b337d46056b7a1281b64c649d592ccda0a9cffd34d9fb01cae1fba61aeed184c817442a2186d5172416729a4b54dd4b84e', @@ -142,44 +142,44 @@ def test_verify_unsupported_crypto_type(self): ) self.assertRaises(ConfigurationError, keypair.verify, "0x1234", '0x1234') - def test_sign_and_verify_incorrect_signature(self): + async def test_sign_and_verify_incorrect_signature(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic) signature = "0x4c291bfb0bb9c1274e86d4b666d13b2ac99a0bacc04a4846fb8ea50bda114677f83c1f164af58fc184451e5140cc8160c4de626163b11451d3bbb208a1889f8a" self.assertFalse(keypair.verify("Test123", signature)) - def test_sign_and_verify_invalid_signature(self): + async def test_sign_and_verify_invalid_signature(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic) signature = "Test" self.assertRaises(TypeError, keypair.verify, "Test123", signature) - def test_sign_and_verify_invalid_message(self): + async def test_sign_and_verify_invalid_message(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic) signature = keypair.sign("Test123") self.assertFalse(keypair.verify("OtherMessage", signature)) - def test_create_ed25519_keypair(self): + async def test_create_ed25519_keypair(self): mnemonic = "old leopard transfer rib spatial phone calm indicate online fire caution review" keypair = Keypair.create_from_mnemonic(mnemonic, ss58_format=0, crypto_type=KeypairType.ED25519) self.assertEqual("16dYRUXznyhvWHS1ktUENGfNAEjCawyDzHRtN9AdFnJRc38h", keypair.ss58_address) - def test_sign_and_verify_ed25519(self): + async def test_sign_and_verify_ed25519(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic, crypto_type=KeypairType.ED25519) signature = keypair.sign("Test123") self.assertTrue(keypair.verify("Test123", signature)) - def test_sign_and_verify_invalid_signature_ed25519(self): + async def test_sign_and_verify_invalid_signature_ed25519(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic, crypto_type=KeypairType.ED25519) signature = "0x4c291bfb0bb9c1274e86d4b666d13b2ac99a0bacc04a4846fb8ea50bda114677f83c1f164af58fc184451e5140cc8160c4de626163b11451d3bbb208a1889f8a" self.assertFalse(keypair.verify("Test123", signature)) - def test_create_ecdsa_keypair_private_key(self): + async def test_create_ecdsa_keypair_private_key(self): private_key = bytes.fromhex("b516d07cbf975a08adf9465c4864b6d7e348b04c241db5eb8f24d89de629d387") keypair = Keypair.create_from_private_key(private_key=private_key, crypto_type=KeypairType.ECDSA) @@ -187,7 +187,7 @@ def test_create_ecdsa_keypair_private_key(self): self.assertEqual("0xc6A0d8799D596BDd5C30E9ACbe2c63F37c142e35", keypair.ss58_address) self.assertEqual(bytes.fromhex("c6A0d8799D596BDd5C30E9ACbe2c63F37c142e35"), keypair.public_key) - def test_create_ecdsa_keypair_mnemonic(self): + async def test_create_ecdsa_keypair_mnemonic(self): mnemonic = "old leopard transfer rib spatial phone calm indicate online fire caution review" # m/44'/60'/0'/0/0 @@ -195,7 +195,7 @@ def test_create_ecdsa_keypair_mnemonic(self): self.assertEqual("0xc6A0d8799D596BDd5C30E9ACbe2c63F37c142e35", keypair.ss58_address) - def test_create_ecdsa_keypair_uri(self): + async def test_create_ecdsa_keypair_uri(self): mnemonic = "old leopard transfer rib spatial phone calm indicate online fire caution review" suri_0 = f"{mnemonic}/m/44'/60'/0'/0/0" @@ -210,34 +210,34 @@ def test_create_ecdsa_keypair_uri(self): self.assertEqual("0x571DCd75Cd50852db08951e3A173aC23e44F05c9", keypair.ss58_address) - def test_sign_and_verify_ecdsa(self): + async def test_sign_and_verify_ecdsa(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic, crypto_type=KeypairType.ECDSA) signature = keypair.sign("Test123") self.assertTrue(keypair.verify("Test123", signature)) - def test_sign_and_verify_invalid_signature_ecdsa(self): + async def test_sign_and_verify_invalid_signature_ecdsa(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic, crypto_type=KeypairType.ECDSA) signature = "0x24ff874fddab207ac6cae6a5bfe6e3542bb561abc98a22d1cfd7f8396927cf6d4962e198b5d599cf598b3c14cca98ab16d12569b666e8d33899c46d0d814a58200" self.assertFalse(keypair.verify("Test123", signature)) - def test_unsupport_crypto_type(self): + async def test_unsupport_crypto_type(self): self.assertRaises( ValueError, Keypair.create_from_seed, seed_hex='0xda3cf5b1e9144931?a0f0db65664aab662673b099415a7f8121b7245fb0be4143', crypto_type=2 ) - def test_sign_and_verify_bytes(self): + async def test_sign_and_verify_bytes(self): mnemonic = Keypair.generate_mnemonic() keypair = Keypair.create_from_mnemonic(mnemonic) signature = keypair.sign(b"Test123") self.assertTrue(keypair.verify(b"Test123", signature)) - def test_sign_and_verify_public_ss58_address(self): + async def test_sign_and_verify_public_ss58_address(self): keypair = Keypair.create_from_uri("//Alice", crypto_type=KeypairType.SR25519) signature = keypair.sign('test') @@ -245,21 +245,21 @@ def test_sign_and_verify_public_ss58_address(self): crypto_type=KeypairType.SR25519) self.assertTrue(keypair_public.verify('test', signature)) - def test_sign_and_verify_public_ethereum_address(self): + async def test_sign_and_verify_public_ethereum_address(self): keypair = Keypair.create_from_uri("/m/44'/60/0'/0", crypto_type=KeypairType.ECDSA) signature = keypair.sign('test') keypair_public = Keypair(public_key='0x5e20a619338338772e97aa444e001043da96a43b', crypto_type=KeypairType.ECDSA) self.assertTrue(keypair_public.verify('test', signature)) - def test_create_keypair_from_private_key(self): + async def test_create_keypair_from_private_key(self): keypair = Keypair.create_from_private_key( ss58_address='16ADqpMa4yzfmWs3nuTSMhfZ2ckeGtvqhPWCNqECEGDcGgU2', private_key='0x1f1995bdf3a17b60626a26cfe6f564b337d46056b7a1281b64c649d592ccda0a9cffd34d9fb01cae1fba61aeed184c817442a2186d5172416729a4b54dd4b84e' ) self.assertEqual(keypair.public_key, bytes.fromhex('e4359ad3e2716c539a1d663ebd0a51bdc5c98a12e663bb4c4402db47828c9446')) - def test_hdkd_hard_path(self): + async def test_hdkd_hard_path(self): mnemonic = 'old leopard transfer rib spatial phone calm indicate online fire caution review' derivation_address = '5FEiH8iuDUw271xbqWTWuB6WrDjv5dnCeDX1CyHubAniXDNN' derivation_path = '//Alice' @@ -268,7 +268,7 @@ def test_hdkd_hard_path(self): self.assertEqual(derivation_address, derived_keypair.ss58_address) - def test_hdkd_soft_path(self): + async def test_hdkd_soft_path(self): mnemonic = 'old leopard transfer rib spatial phone calm indicate online fire caution review' derivation_address = '5GNXbA46ma5dg19GXdiKi5JH3mnkZ8Yea3bBtZAvj7t99P9i' derivation_path = '/Alice' @@ -277,7 +277,7 @@ def test_hdkd_soft_path(self): self.assertEqual(derivation_address, derived_keypair.ss58_address) - def test_hdkd_default_to_dev_mnemonic(self): + async def test_hdkd_default_to_dev_mnemonic(self): derivation_address = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY' derivation_path = '//Alice' @@ -285,7 +285,7 @@ def test_hdkd_default_to_dev_mnemonic(self): self.assertEqual(derivation_address, derived_keypair.ss58_address) - def test_hdkd_create_uri_correct_ss58format(self): + async def test_hdkd_create_uri_correct_ss58format(self): derivation_address = 'HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F' derivation_path = '//Alice' @@ -294,7 +294,7 @@ def test_hdkd_create_uri_correct_ss58format(self): self.assertEqual(derived_keypair.ss58_format, 2) self.assertEqual(derived_keypair.ss58_address, derivation_address) - def test_hdkd_nested_hard_soft_path(self): + async def test_hdkd_nested_hard_soft_path(self): derivation_address = '5CJGwWiKXSE16WJaxBdPZhWqUYkotgenLUALv7ZvqQ4TXeqf' derivation_path = '//Bob/test' @@ -302,7 +302,7 @@ def test_hdkd_nested_hard_soft_path(self): self.assertEqual(derivation_address, derived_keypair.ss58_address) - def test_hdkd_nested_soft_hard_path(self): + async def test_hdkd_nested_soft_hard_path(self): derivation_address = '5Cwc8tShrshDJUp1P1M21dKUTcYQpV9GcfSa4hUBNmMdV3Cx' derivation_path = '/Bob//test' @@ -310,7 +310,7 @@ def test_hdkd_nested_soft_hard_path(self): self.assertEqual(derivation_address, derived_keypair.ss58_address) - def test_hdkd_nested_numeric_hard_path(self): + async def test_hdkd_nested_numeric_hard_path(self): derivation_address = '5Fc3qszVcAXHAmjjm61KcxqvV1kh91jpydE476NjjnJneNdP' derivation_path = '//polkadot//0' @@ -318,7 +318,7 @@ def test_hdkd_nested_numeric_hard_path(self): self.assertEqual(derivation_address, derived_keypair.ss58_address) - def test_hdkd_nested_numeric2_hard_path(self): + async def test_hdkd_nested_numeric2_hard_path(self): derivation_address = '5Dr9GrefZzxfeHovyiKUXKYGKRRiTbPhfLo14iYcHKNccN9q' derivation_path = '//1//5000' @@ -326,7 +326,7 @@ def test_hdkd_nested_numeric2_hard_path(self): self.assertEqual(derivation_address, derived_keypair.ss58_address) - def test_hdkd_path_gt_32_bytes(self): + async def test_hdkd_path_gt_32_bytes(self): derivation_address = '5GR5pfZeNs1uQiSWVxZaQiZou3wdZiX894eqgvfNfHbEh7W2' derivation_path = '//PathNameLongerThan32BytesWhichShouldBeHashed' @@ -334,7 +334,7 @@ def test_hdkd_path_gt_32_bytes(self): self.assertEqual(derivation_address, derived_keypair.ss58_address) - def test_hdkd_path_eq_32_bytes(self): + async def test_hdkd_path_eq_32_bytes(self): derivation_address = '5Ea3JZpvsBN34jiQwVrLiMh5ypaHtPSyM2DWQvLmSRioEmyk' derivation_path = '//rococo-validator-profiled-node-0' @@ -342,14 +342,14 @@ def test_hdkd_path_eq_32_bytes(self): self.assertEqual(derivation_address, derived_keypair.ss58_address) - def test_hdkd_unsupported_password(self): + async def test_hdkd_unsupported_password(self): self.assertRaises(NotImplementedError, Keypair.create_from_uri, DEV_PHRASE + '///test') - def test_reconstruct_path_fail(self): + async def test_reconstruct_path_fail(self): self.assertRaises(ValueError, extract_derive_path, 'no_slashes') self.assertRaises(ValueError, extract_derive_path, '//') - def test_encrypt_decrypt_message(self): + async def test_encrypt_decrypt_message(self): sender = Keypair.create_from_mnemonic("nominee lift horse divert crop quantum proud between pink goose attack market", crypto_type=KeypairType.ED25519) recipient = Keypair(ss58_address="5DFZ8UzF5zeCLVPVRMkopNjVyxJNb1dHgGJYFDaVbm4CqNku", crypto_type=KeypairType.ED25519) message = "Violence is the last refuge of the incompetent - Isaac Asimov, Foundation" @@ -359,7 +359,7 @@ def test_encrypt_decrypt_message(self): message_decrypted = recipient.decrypt_message(message_encrypted, sender.public_key).decode("utf-8") self.assertEqual(message_decrypted, message) - def test_hdkd_multi_lang(self): + async def test_hdkd_multi_lang(self): mnemonic_path = "秘 心 姜 封 迈 走 描 朗 出 莫 人 口//0" keypair = Keypair.create_from_uri(mnemonic_path, language_code=MnemonicLanguageCode.CHINESE_SIMPLIFIED) self.assertNotEqual(keypair, None) @@ -374,7 +374,7 @@ def test_hdkd_multi_lang(self): keypair = Keypair.create_from_uri(mnemonic_path, language_code=MnemonicLanguageCode.FRENCH) self.assertNotEqual(keypair, None) - def test_create_from_encrypted_json(self): + async def test_create_from_encrypted_json(self): keypair_alice = Keypair.create_from_uri('//Alice') @@ -390,7 +390,7 @@ def test_create_from_encrypted_json(self): signature = keypair.sign("Test123") self.assertTrue(keypair.verify("Test123", signature)) - def test_create_from_encrypted_json_ed25519(self): + async def test_create_from_encrypted_json_ed25519(self): json_file = os.path.join(os.path.dirname(__file__), 'fixtures', 'polkadotjs_encrypted_ed25519.json') with open(json_file, 'r') as fp: json_data = fp.read() @@ -400,7 +400,7 @@ def test_create_from_encrypted_json_ed25519(self): signature = keypair.sign("Test123") self.assertTrue(keypair.verify("Test123", signature)) - def test_export_keypair_to_json(self): + async def test_export_keypair_to_json(self): keypair = Keypair.create_from_uri('//Alice') json_data = keypair.export_to_encrypted_json(passphrase="test", name="Alice") diff --git a/test/test_query.py b/test/test_query.py index 3c4a4ea..538160f 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -15,14 +15,13 @@ # limitations under the License. import unittest -from unittest.mock import MagicMock from substrateinterface import SubstrateInterface from substrateinterface.exceptions import StorageFunctionNotFound from test import settings -class QueryTestCase(unittest.TestCase): +class QueryTestCase(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): @@ -38,9 +37,9 @@ def setUpClass(cls): type_registry_preset='polkadot' ) - def test_system_account(self): + async def test_system_account(self): - result = self.kusama_substrate.query( + result = await self.kusama_substrate.query( module='System', storage_function='Account', params=['F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T'], @@ -51,8 +50,8 @@ def test_system_account(self): self.assertEqual(1099945000512, result.value['data']['free']) self.assertEqual(result.meta_info['result_found'], True) - def test_system_account_non_existing(self): - result = self.kusama_substrate.query( + async def test_system_account_non_existing(self): + result = await self.kusama_substrate.query( module='System', storage_function='Account', params=['GSEX8kR4Kz5UZGhvRUCJG93D5hhTAoVZ5tAe6Zne7V42DSi'] @@ -66,18 +65,18 @@ def test_system_account_non_existing(self): } }, result.value) - def test_non_existing_query(self): + async def test_non_existing_query(self): with self.assertRaises(StorageFunctionNotFound) as cm: - self.kusama_substrate.query("Unknown", "StorageFunction") + await self.kusama_substrate.query("Unknown", "StorageFunction") self.assertEqual('Pallet "Unknown" not found', str(cm.exception)) - def test_missing_params(self): - with self.assertRaises(ValueError) as cm: - self.kusama_substrate.query("System", "Account") + async def test_missing_params(self): + with self.assertRaises(ValueError): + await self.kusama_substrate.query("System", "Account") - def test_modifier_default_result(self): - result = self.kusama_substrate.query( + async def test_modifier_default_result(self): + result = await self.kusama_substrate.query( module='Staking', storage_function='HistoryDepth', block_hash='0x4b313e72e3a524b98582c31cd3ff6f7f2ef5c38a3c899104a833e468bb1370a2' @@ -86,9 +85,9 @@ def test_modifier_default_result(self): self.assertEqual(84, result.value) self.assertEqual(result.meta_info['result_found'], False) - def test_modifier_option_result(self): + async def test_modifier_option_result(self): - result = self.kusama_substrate.query( + result = await self.kusama_substrate.query( module='Identity', storage_function='IdentityOf', params=["DD6kXYJPHbPRbBjeR35s1AR7zDh7W2aE55EBuDyMorQZS2a"], @@ -98,57 +97,57 @@ def test_modifier_option_result(self): self.assertIsNone(result.value) self.assertEqual(result.meta_info['result_found'], False) - def test_identity_hasher(self): - result = self.kusama_substrate.query("Claims", "Claims", ["0x00000a9c44f24e314127af63ae55b864a28d7aee"]) + async def test_identity_hasher(self): + result = await self.kusama_substrate.query("Claims", "Claims", ["0x00000a9c44f24e314127af63ae55b864a28d7aee"]) self.assertEqual(45880000000000, result.value) - def test_well_known_keys_result(self): - result = self.kusama_substrate.query("Substrate", "Code") + async def test_well_known_keys_result(self): + result = await self.kusama_substrate.query("Substrate", "Code") self.assertIsNotNone(result.value) - def test_well_known_keys_default(self): - result = self.kusama_substrate.query("Substrate", "HeapPages") + async def test_well_known_keys_default(self): + result = await self.kusama_substrate.query("Substrate", "HeapPages") self.assertEqual(0, result.value) - def test_well_known_keys_not_found(self): + async def test_well_known_keys_not_found(self): with self.assertRaises(StorageFunctionNotFound): - self.kusama_substrate.query("Substrate", "Unknown") + await self.kusama_substrate.query("Substrate", "Unknown") - def test_well_known_pallet_version(self): + async def test_well_known_pallet_version(self): - sf = self.kusama_substrate.get_metadata_storage_function("Balances", "PalletVersion") + sf = await self.kusama_substrate.get_metadata_storage_function("Balances", "PalletVersion") self.assertEqual(sf.value['name'], ':__STORAGE_VERSION__:') - result = self.kusama_substrate.query("Balances", "PalletVersion") + result = await self.kusama_substrate.query("Balances", "PalletVersion") self.assertGreaterEqual(result.value, 1) - def test_query_multi(self): + async def test_query_multi(self): storage_keys = [ - self.kusama_substrate.create_storage_key( + await self.kusama_substrate.create_storage_key( "System", "Account", ["F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T"] ), - self.kusama_substrate.create_storage_key( + await self.kusama_substrate.create_storage_key( "System", "Account", ["GSEX8kR4Kz5UZGhvRUCJG93D5hhTAoVZ5tAe6Zne7V42DSi"] ), - self.kusama_substrate.create_storage_key( + await self.kusama_substrate.create_storage_key( "Staking", "Bonded", ["GSEX8kR4Kz5UZGhvRUCJG93D5hhTAoVZ5tAe6Zne7V42DSi"] ) ] - result = self.kusama_substrate.query_multi(storage_keys) + result = await self.kusama_substrate.query_multi(storage_keys) self.assertEqual(len(result), 3) self.assertEqual(result[0][0].params[0], "F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T") self.assertGreater(result[0][1].value['nonce'], 0) self.assertEqual(result[1][1].value['nonce'], 0) - def test_storage_key_unknown(self): + async def test_storage_key_unknown(self): with self.assertRaises(StorageFunctionNotFound): - self.kusama_substrate.create_storage_key("Unknown", "Unknown") + await self.kusama_substrate.create_storage_key("Unknown", "Unknown") with self.assertRaises(StorageFunctionNotFound): - self.kusama_substrate.create_storage_key("System", "Unknown") + await self.kusama_substrate.create_storage_key("System", "Unknown") if __name__ == '__main__': diff --git a/test/test_query_map.py b/test/test_query_map.py index 693ea2e..11cd7fb 100644 --- a/test/test_query_map.py +++ b/test/test_query_map.py @@ -15,9 +15,9 @@ # limitations under the License. import unittest -from unittest.mock import MagicMock +from unittest.mock import AsyncMock -from scalecodec.types import GenericAccountId +from scalecodec.types import GenericAccountId # type: ignore[import-untyped] from substrateinterface.exceptions import SubstrateRequestException @@ -25,7 +25,7 @@ from test import settings -class QueryMapTestCase(unittest.TestCase): +class QueryMapTestCase(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): @@ -38,7 +38,7 @@ def setUpClass(cls): orig_rpc_request = cls.kusama_substrate.rpc_request - def mocked_request(method, params): + async def mocked_request(method, params): if method == 'state_getKeysPaged': if params[3] == '0x2e8047826d028f5cc092f5e694860efbd4f74ee1535424cdf3626a175867db62': @@ -60,13 +60,13 @@ def mocked_request(method, params): ], 'id': 8 } - return orig_rpc_request(method, params) + return await orig_rpc_request(method, params) - cls.kusama_substrate.rpc_request = MagicMock(side_effect=mocked_request) + cls.kusama_substrate.rpc_request = AsyncMock(side_effect=mocked_request) - def test_claims_claim_map(self): + async def test_claims_claim_map(self): - result = self.kusama_substrate.query_map('Claims', 'Claims', max_results=3) + result = await self.kusama_substrate.query_map('Claims', 'Claims', max_results=3) records = [item for item in result] @@ -76,16 +76,16 @@ def test_claims_claim_map(self): self.assertEqual('0x00002f21194993a750972574e2d82ce8c95078a6', records[1][0].value) self.assertEqual('0x0000a940f973ccf435ae9c040c253e1c043c5fb2', records[2][0].value) - def test_system_account_map_block_hash(self): + async def test_system_account_map_block_hash(self): # Retrieve first two records from System.Account query map - result = self.kusama_substrate.query_map( + result = await self.kusama_substrate.query_map( 'System', 'Account', page_size=1, block_hash="0x587a1e69871c09f2408d724ceebbe16edc4a69139b5df9786e1057c4d041af73" ) - record_1_1 = next(result) + record_1_1 = await result.__anext__() self.assertEqual(type(record_1_1[0]), GenericAccountId) self.assertIn('data', record_1_1[1].value) @@ -93,7 +93,7 @@ def test_system_account_map_block_hash(self): # Next record set must trigger RPC call - record_1_2 = next(result) + record_1_2 = await result.__anext__() self.assertEqual(type(record_1_2[0]), GenericAccountId) self.assertIn('data', record_1_2[1].value) @@ -101,34 +101,34 @@ def test_system_account_map_block_hash(self): # Same query map with yield of 2 must result in same records - result = self.kusama_substrate.query_map( + result = await self.kusama_substrate.query_map( 'System', 'Account', page_size=2, block_hash="0x587a1e69871c09f2408d724ceebbe16edc4a69139b5df9786e1057c4d041af73" ) - record_2_1 = next(result) - record_2_2 = next(result) + record_2_1 = await result.__anext__() + record_2_2 = await result.__anext__() self.assertEqual(record_1_1[0].value, record_2_1[0].value) self.assertEqual(record_1_1[1].value, record_2_1[1].value) self.assertEqual(record_1_2[0].value, record_2_2[0].value) self.assertEqual(record_1_2[1].value, record_2_2[1].value) - def test_max_results(self): - result = self.kusama_substrate.query_map('Claims', 'Claims', max_results=5, page_size=100) + async def test_max_results(self): + result = await self.kusama_substrate.query_map('Claims', 'Claims', max_results=5, page_size=100) # Keep iterating shouldn't trigger retrieve next page result_count = 0 - for _ in result: + async for _ in result: result_count += 1 self.assertEqual(5, result_count) - result = self.kusama_substrate.query_map('Claims', 'Claims', max_results=5, page_size=2) + result = await self.kusama_substrate.query_map('Claims', 'Claims', max_results=5, page_size=2) # Keep iterating shouldn't exceed max_results result_count = 0 - for record in result: + async for record in result: result_count += 1 if result_count == 1: self.assertEqual('0x00000a9c44f24e314127af63ae55b864a28d7aee', record[0].value) @@ -139,8 +139,8 @@ def test_max_results(self): self.assertEqual(5, result_count) - def test_result_exhausted(self): - result = self.kusama_substrate.query_map( + async def test_result_exhausted(self): + result = await self.kusama_substrate.query_map( module='Claims', storage_function='Claims', block_hash='0x2e8047826d028f5cc092f5e694860efbd4f74ee1535424cdf3626a175867db62' ) @@ -151,26 +151,26 @@ def test_result_exhausted(self): self.assertEqual(4, result_count) - def test_non_existing_query_map(self): + async def test_non_existing_query_map(self): with self.assertRaises(ValueError) as cm: - self.kusama_substrate.query_map("Unknown", "StorageFunction") + await self.kusama_substrate.query_map("Unknown", "StorageFunction") self.assertEqual('Pallet "Unknown" not found', str(cm.exception)) - def test_non_map_function_query_map(self): + async def test_non_map_function_query_map(self): with self.assertRaises(ValueError) as cm: - self.kusama_substrate.query_map("System", "Events") + await self.kusama_substrate.query_map("System", "Events") self.assertEqual('Given storage function is not a map', str(cm.exception)) - def test_exceed_maximum_page_size(self): + async def test_exceed_maximum_page_size(self): with self.assertRaises(SubstrateRequestException): - self.kusama_substrate.query_map( + await self.kusama_substrate.query_map( 'System', 'Account', page_size=9999999 ) - def test_double_map(self): - era_stakers = self.kusama_substrate.query_map( + async def test_double_map(self): + era_stakers = await self.kusama_substrate.query_map( module='Staking', storage_function='ErasStakers', params=[2185], @@ -186,8 +186,8 @@ def test_double_map(self): self.assertEqual(records[2][0].ss58_address, 'DfishveZoxSRNRb8FtyS7ignbw6cr32eCY2w6ctLDRM1NQz') self.assertEqual(records[3][0].ss58_address, 'HmsTAS1bCtZc9FSq9nqJzZCEkhhSygtXj9TDxNgEWTHnpyQ') - def test_double_map_page_size(self): - era_stakers = self.kusama_substrate.query_map( + async def test_double_map_page_size(self): + era_stakers = await self.kusama_substrate.query_map( module='Staking', storage_function='ErasStakers', params=[2185], @@ -196,7 +196,9 @@ def test_double_map_page_size(self): block_hash="0x61dd66907df3187fd1438463f2c87f0d596797936e0a292f6f98d12841da2325" ) - records = list(era_stakers) + records = [] + async for i in era_stakers: + records.append(i) self.assertEqual(len(records), 4) self.assertEqual(records[0][0].ss58_address, 'JCghFN7mD4ETKzMbvSVmMMPwWutJGk6Bm1yKWk8Z9KhPGeZ') @@ -204,8 +206,8 @@ def test_double_map_page_size(self): self.assertEqual(records[2][0].ss58_address, 'DfishveZoxSRNRb8FtyS7ignbw6cr32eCY2w6ctLDRM1NQz') self.assertEqual(records[3][0].ss58_address, 'HmsTAS1bCtZc9FSq9nqJzZCEkhhSygtXj9TDxNgEWTHnpyQ') - def test_double_map_no_result(self): - era_stakers = self.kusama_substrate.query_map( + async def test_double_map_no_result(self): + era_stakers = await self.kusama_substrate.query_map( module='Staking', storage_function='ErasStakers', params=[21000000], @@ -213,9 +215,9 @@ def test_double_map_no_result(self): ) self.assertEqual(era_stakers.records, []) - def test_nested_keys(self): + async def test_nested_keys(self): - result = self.kusama_substrate.query_map( + result = await self.kusama_substrate.query_map( module='ConvictionVoting', storage_function='VotingFor', max_results=10 @@ -223,18 +225,18 @@ def test_nested_keys(self): self.assertTrue(self.kusama_substrate.is_valid_ss58_address(result[0][0][0].value)) self.assertGreaterEqual(result[0][0][1], 0) - def test_double_map_too_many_params(self): + async def test_double_map_too_many_params(self): with self.assertRaises(ValueError) as cm: - self.kusama_substrate.query_map( + await self.kusama_substrate.query_map( module='Staking', storage_function='ErasStakers', params=[21000000, 2] ) self.assertEqual('Storage function map can accept max 1 parameters, 2 given', str(cm.exception)) - def test_map_with_param(self): + async def test_map_with_param(self): with self.assertRaises(ValueError) as cm: - self.kusama_substrate.query_map( + await self.kusama_substrate.query_map( module='System', storage_function='Account', params=[2] diff --git a/test/test_rpc_compatibility.py b/test/test_rpc_compatibility.py index 12138de..8c1b2cf 100644 --- a/test/test_rpc_compatibility.py +++ b/test/test_rpc_compatibility.py @@ -15,20 +15,18 @@ # limitations under the License. import os import unittest -from unittest.mock import MagicMock +from unittest.mock import AsyncMock -from scalecodec.type_registry import load_type_registry_file -from test import settings +from scalecodec.type_registry import load_type_registry_file # type: ignore[import-untyped] -from scalecodec.exceptions import RemainingScaleBytesNotEmptyException from substrateinterface import SubstrateInterface -from scalecodec.base import ScaleBytes -from scalecodec.types import Vec, GenericAddress +from scalecodec.base import ScaleBytes # type: ignore[import-untyped] +from scalecodec.types import Vec, GenericAddress # type: ignore[import-untyped] -class RPCCompatilibityTestCase(unittest.TestCase): +class RPCCompatilibityTestCase(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): @@ -41,9 +39,9 @@ def setUpClass(cls): 'MetadataVersioned', ScaleBytes(cls.metadata_fixture_dict['V14']) ) metadata_decoder.decode() - cls.substrate.get_block_metadata = MagicMock(return_value=metadata_decoder) + cls.substrate.get_block_metadata = AsyncMock(return_value=metadata_decoder) - def mocked_query(module, storage_function, block_hash): + async def mocked_query(module, storage_function, block_hash): if module == 'Session' and storage_function == 'Validators': if block_hash == '0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93': vec = Vec() @@ -54,7 +52,7 @@ def mocked_query(module, storage_function, block_hash): raise ValueError(f"Unsupported mocked query {module}.{storage_function} @ {block_hash}") - def mocked_request(method, params, result_handler=None): + async def mocked_request(method, params, result_handler=None): if method in ['chain_getBlockHash', 'chain_getHead', 'chain_getFinalisedHead', 'chain_getFinalizedHead']: return { @@ -160,19 +158,48 @@ def mocked_request(method, params, result_handler=None): "result": {"methods": ['author_submitExtrinsic', 'author_submitAndWatchExtrinsic', 'author_unwatchExtrinsic', 'author_pendingExtrinsics', 'chain_getBlockHash', 'chain_getHeader', 'chain_getBlock', 'chain_getFinalizedHead', 'chain_subscribeNewHead', 'chain_subscribeFinalizedHeads', 'chain_unsubscribeNewHead', 'chain_subscribeNewHeads', 'chain_unsubscribeNewHeads', 'chain_unsubscribeFinalizedHeads', 'state_getRuntimeVersion', 'state_getMetadata', 'state_getStorage', 'state_getKeysPaged', 'state_queryStorageAt', 'state_call', 'state_subscribeRuntimeVersion', 'state_unsubscribeRuntimeVersion', 'state_subscribeStorage', 'state_unsubscribeStorage', 'system_localPeerId', 'system_nodeRoles', 'system_localListenAddresses', 'system_chain', 'system_properties', 'system_name', 'system_version', 'system_chainType', 'system_health', 'system_dryRun', 'system_accountNextIndex', 'payment_queryFeeDetails', 'payment_queryInfo', 'dev_newBlock', 'dev_setStorage', 'dev_timeTravel', 'dev_setHead', 'dev_dryRun', 'rpc_methods']}, "id": 1 } + # FIXME: Random data + elif method == 'system_name': + return { + "jsonrpc": "2.0", + "result": "substrate-node", + "id": 1 + } + elif method == 'system_properties': + return { + "jsonrpc": "2.0", + "result": { + "ss58Format": 42, + "tokenDecimals": 12, + "tokenSymbol": "KSM" + }, + "id": 1 + } + elif method == 'system_chain': + return { + "jsonrpc": "2.0", + "result": "Ethereum", + "id": 1 + } + elif method == 'system_version': + return { + "jsonrpc": "2.0", + "result": "substrate-node", + "id": 1, + } raise ValueError(f"Unsupported mocked method {method}") - cls.substrate.rpc_request = MagicMock(side_effect=mocked_request) - cls.substrate.query = MagicMock(side_effect=mocked_query) + cls.substrate.rpc_request = AsyncMock(side_effect=mocked_request) + cls.substrate.query = AsyncMock(side_effect=mocked_query) - def test_get_block_by_head(self): + async def test_get_block_by_head(self): - block = self.substrate.get_block() + block = await self.substrate.get_block() self.assertEqual('0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', block['header']['hash']) - def test_get_chain_head(self): - block_hash = self.substrate.get_chain_head() + async def test_get_chain_head(self): + block_hash = await self.substrate.get_chain_head() self.assertEqual('0xec828914eca09331dad704404479e2899a971a9b5948345dc40abca4ac818f93', block_hash) diff --git a/test/test_runtime_call.py b/test/test_runtime_call.py index 404f792..3e9349e 100644 --- a/test/test_runtime_call.py +++ b/test/test_runtime_call.py @@ -15,14 +15,12 @@ # limitations under the License. import unittest -from unittest.mock import MagicMock from substrateinterface import SubstrateInterface, Keypair -from substrateinterface.exceptions import StorageFunctionNotFound from test import settings -class RuntimeCallTestCase(unittest.TestCase): +class RuntimeCallTestCase(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): @@ -35,21 +33,21 @@ def setUpClass(cls): mnemonic = Keypair.generate_mnemonic() cls.keypair = Keypair.create_from_mnemonic(mnemonic) - def test_core_version(self): - result = self.substrate.runtime_call("Core", "version") + async def test_core_version(self): + result = await self.substrate.runtime_call("Core", "version") self.assertGreater(result.value['spec_version'], 0) self.assertEqual('polkadot', result.value['spec_name']) - def test_core_version_at_not_best_block(self): - parent_hash = self.substrate.get_block_header()['header']['parentHash'] - result = self.substrate.runtime_call("Core", "version", block_hash = parent_hash) + async def test_core_version_at_not_best_block(self): + parent_hash = (await self.substrate.get_block_header())['header']['parentHash'] + result = await self.substrate.runtime_call("Core", "version", block_hash = parent_hash) self.assertGreater(result.value['spec_version'], 0) self.assertEqual('polkadot', result.value['spec_name']) - def test_transaction_payment(self): - call = self.substrate.compose_call( + async def test_transaction_payment(self): + call = await self.substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -58,39 +56,39 @@ def test_transaction_payment(self): } ) - extrinsic = self.substrate.create_signed_extrinsic(call=call, keypair=self.keypair, tip=1) - extrinsic_len = self.substrate.create_scale_object('u32') + extrinsic = await self.substrate.create_signed_extrinsic(call=call, keypair=self.keypair, tip=1) + extrinsic_len = await self.substrate.create_scale_object('u32') extrinsic_len.encode(len(extrinsic.data)) - result = self.substrate.runtime_call("TransactionPaymentApi", "query_fee_details", [extrinsic, extrinsic_len]) + result = await self.substrate.runtime_call("TransactionPaymentApi", "query_fee_details", [extrinsic, extrinsic_len]) self.assertGreater(result.value['inclusion_fee']['base_fee'], 0) self.assertEqual(0, result.value['tip']) - def test_metadata_call_info(self): + async def test_metadata_call_info(self): - runtime_call = self.substrate.get_metadata_runtime_call_function("TransactionPaymentApi", "query_fee_details") + runtime_call = await self.substrate.get_metadata_runtime_call_function("TransactionPaymentApi", "query_fee_details") param_info = runtime_call.get_param_info() self.assertEqual('Extrinsic', param_info[0]) self.assertEqual('u32', param_info[1]) - runtime_call = self.substrate.get_metadata_runtime_call_function("Core", "initialise_block") + runtime_call = await self.substrate.get_metadata_runtime_call_function("Core", "initialise_block") param_info = runtime_call.get_param_info() self.assertEqual('u32', param_info[0]['number']) self.assertEqual('h256', param_info[0]['parent_hash']) - def test_check_all_runtime_call_types(self): - runtime_calls = self.substrate.get_metadata_runtime_call_functions() + async def test_check_all_runtime_call_types(self): + runtime_calls = await self.substrate.get_metadata_runtime_call_functions() for runtime_call in runtime_calls: param_info = runtime_call.get_param_info() self.assertEqual(type(param_info), list) - result_obj = self.substrate.create_scale_object(runtime_call.value['type']) + result_obj = await self.substrate.create_scale_object(runtime_call.value['type']) info = result_obj.generate_type_decomposition() self.assertIsNotNone(info) - def test_unknown_runtime_call(self): + async def test_unknown_runtime_call(self): with self.assertRaises(ValueError): - self.substrate.runtime_call("Foo", "bar") + await self.substrate.runtime_call("Foo", "bar") if __name__ == '__main__': diff --git a/test/test_ss58.py b/test/test_ss58.py index c08e277..8425131 100644 --- a/test/test_ss58.py +++ b/test/test_ss58.py @@ -22,7 +22,9 @@ from substrateinterface import Keypair -class SS58TestCase(unittest.TestCase): +class SS58TestCase(unittest.IsolatedAsyncioTestCase): + alice_keypair: Keypair + subkey_pairs: list @classmethod def setUpClass(cls) -> None: @@ -63,46 +65,46 @@ def setUpClass(cls) -> None: } ] - def test_encode_key_pair_alice_address(self): + async def test_encode_key_pair_alice_address(self): self.assertEqual(self.alice_keypair.ss58_address, "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") - def test_encode_1_byte_account_index(self): + async def test_encode_1_byte_account_index(self): self.assertEqual('F7NZ', ss58_encode_account_index(1)) - def test_encode_1_byte_account_index_with_format(self): + async def test_encode_1_byte_account_index_with_format(self): self.assertEqual('g4b', ss58_encode_account_index(1, ss58_format=2)) self.assertEqual('g4b', ss58_encode('0x01', ss58_format=2)) - def test_encode_2_bytes_account_index(self): + async def test_encode_2_bytes_account_index(self): self.assertEqual('3xygo', ss58_encode_account_index(256, ss58_format=2)) self.assertEqual('3xygo', ss58_encode('0x0001', ss58_format=2)) - def test_encode_4_bytes_account_index(self): + async def test_encode_4_bytes_account_index(self): self.assertEqual('zswfoZa', ss58_encode_account_index(67305985, ss58_format=2)) self.assertEqual('zswfoZa', ss58_encode('0x01020304', ss58_format=2)) - def test_encode_8_bytes_account_index(self): + async def test_encode_8_bytes_account_index(self): self.assertEqual('848Gh2GcGaZia', ss58_encode('0x2a2c0a0000000000', ss58_format=2)) - def test_decode_1_byte_account_index(self): + async def test_decode_1_byte_account_index(self): self.assertEqual(1, ss58_decode_account_index('F7NZ')) - def test_decode_2_bytes_account_index(self): + async def test_decode_2_bytes_account_index(self): self.assertEqual(256, ss58_decode_account_index('3xygo')) - def test_decode_4_bytes_account_index(self): + async def test_decode_4_bytes_account_index(self): self.assertEqual(67305985, ss58_decode_account_index('zswfoZa')) - def test_decode_8_bytes_account_index(self): + async def test_decode_8_bytes_account_index(self): self.assertEqual(666666, ss58_decode_account_index('848Gh2GcGaZia')) - def test_encode_33_byte_address(self): + async def test_encode_33_byte_address(self): self.assertEqual( 'KWCv1L3QX9LDPwY4VzvLmarEmXjVJidUzZcinvVnmxAJJCBou', ss58_encode('0x03b9dc646dd71118e5f7fda681ad9eca36eb3ee96f344f582fbe7b5bcdebb13077') ) - def test_encode_with_2_byte_prefix(self): + async def test_encode_with_2_byte_prefix(self): public_key = ss58_decode('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaQua') self.assertEqual( @@ -110,21 +112,21 @@ def test_encode_with_2_byte_prefix(self): ss58_encode(public_key, ss58_format=255) ) - def test_encode_subkey_generated_pairs(self): + async def test_encode_subkey_generated_pairs(self): for subkey_pair in self.subkey_pairs: self.assertEqual( subkey_pair['address'], ss58_encode(address=subkey_pair['public_key'], ss58_format=subkey_pair['ss58_format']) ) - def test_decode_subkey_generated_pairs(self): + async def test_decode_subkey_generated_pairs(self): for subkey_pair in self.subkey_pairs: self.assertEqual( subkey_pair['public_key'], '0x' + ss58_decode(address=subkey_pair['address'], valid_ss58_format=subkey_pair['ss58_format']) ) - def test_invalid_ss58_format_range_exceptions(self): + async def test_invalid_ss58_format_range_exceptions(self): with self.assertRaises(ValueError) as cm: ss58_encode(self.alice_keypair.public_key, ss58_format=-1) @@ -135,7 +137,7 @@ def test_invalid_ss58_format_range_exceptions(self): self.assertEqual('Invalid value for ss58_format', str(cm.exception)) - def test_invalid_reserved_ss58_format(self): + async def test_invalid_reserved_ss58_format(self): with self.assertRaises(ValueError) as cm: ss58_encode(self.alice_keypair.public_key, ss58_format=46) @@ -146,19 +148,19 @@ def test_invalid_reserved_ss58_format(self): self.assertEqual('Invalid value for ss58_format', str(cm.exception)) - def test_invalid_public_key(self): + async def test_invalid_public_key(self): with self.assertRaises(ValueError) as cm: ss58_encode(self.alice_keypair.public_key[:30]) self.assertEqual('Invalid length for address', str(cm.exception)) - def test_decode_public_key(self): + async def test_decode_public_key(self): self.assertEqual( '0x03b9dc646dd71118e5f7fda681ad9eca36eb3ee96f344f582fbe7b5bcdebb13077', ss58_decode('0x03b9dc646dd71118e5f7fda681ad9eca36eb3ee96f344f582fbe7b5bcdebb13077') ) - def test_decode_reserved_ss58_formats(self): + async def test_decode_reserved_ss58_formats(self): with self.assertRaises(ValueError) as cm: ss58_decode('MGP3U1wqNhFofseKXU7B6FcZuLbvQvJFyin1EvQM65mBcNsY8') @@ -169,31 +171,31 @@ def test_decode_reserved_ss58_formats(self): self.assertEqual('47 is a reserved SS58 format', str(cm.exception)) - def test_invalid_ss58_format_check(self): + async def test_invalid_ss58_format_check(self): with self.assertRaises(ValueError) as cm: ss58_decode('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaQua', valid_ss58_format=2) self.assertEqual('Invalid SS58 format', str(cm.exception)) - def test_decode_invalid_checksum(self): + async def test_decode_invalid_checksum(self): with self.assertRaises(ValueError) as cm: ss58_decode('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaQub') self.assertEqual('Invalid checksum', str(cm.exception)) - def test_decode_invalid_length(self): + async def test_decode_invalid_length(self): with self.assertRaises(ValueError) as cm: ss58_decode('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaQubsdhfjksdhfkj') self.assertEqual('Invalid address length', str(cm.exception)) - def test_decode_empty_string(self): + async def test_decode_empty_string(self): with self.assertRaises(ValueError) as cm: ss58_decode('') self.assertEqual('Empty address provided', str(cm.exception)) - def test_is_valid_ss58_address(self): + async def test_is_valid_ss58_address(self): self.assertTrue(is_valid_ss58_address('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY')) self.assertTrue(is_valid_ss58_address('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', valid_ss58_format=42)) self.assertFalse(is_valid_ss58_address('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', valid_ss58_format=2)) diff --git a/test/test_subscriptions.py b/test/test_subscriptions.py index e8150c7..8e330fc 100644 --- a/test/test_subscriptions.py +++ b/test/test_subscriptions.py @@ -20,7 +20,7 @@ from test import settings -class SubscriptionsTestCase(unittest.TestCase): +class SubscriptionsTestCase(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): @@ -28,42 +28,42 @@ def setUpClass(cls): url=settings.POLKADOT_NODE_URL ) - def test_query_subscription(self): + async def test_query_subscription(self): - def subscription_handler(obj, update_nr, subscription_id): + async def subscription_handler(obj, update_nr, subscription_id): return {'update_nr': update_nr, 'subscription_id': subscription_id} - result = self.substrate.query("System", "Events", [], subscription_handler=subscription_handler) + result = await self.substrate.query("System", "Events", [], subscription_handler=subscription_handler) self.assertIsNotNone(result['subscription_id']) - def test_subscribe_storage_multi(self): + async def test_subscribe_storage_multi(self): - def subscription_handler(storage_key, updated_obj, update_nr, subscription_id): + async def subscription_handler(storage_key, updated_obj, update_nr, subscription_id): return {'update_nr': update_nr, 'subscription_id': subscription_id} storage_keys = [ - self.substrate.create_storage_key( + await self.substrate.create_storage_key( "System", "Account", ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"] ), - self.substrate.create_storage_key( + await self.substrate.create_storage_key( "System", "Account", ["5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"] ) ] - result = self.substrate.subscribe_storage( + result = await self.substrate.subscribe_storage( storage_keys=storage_keys, subscription_handler=subscription_handler ) self.assertIsNotNone(result['subscription_id']) - def test_subscribe_new_heads(self): + async def test_subscribe_new_heads(self): - def block_subscription_handler(obj, update_nr, subscription_id): + async def block_subscription_handler(obj, update_nr, subscription_id): return obj['header']['number'] - result = self.substrate.subscribe_block_headers(block_subscription_handler, finalized_only=True) + result = await self.substrate.subscribe_block_headers(block_subscription_handler, finalized_only=True) self.assertGreater(result, 0) diff --git a/test/test_type_registry.py b/test/test_type_registry.py index 321a97a..6c894ee 100644 --- a/test/test_type_registry.py +++ b/test/test_type_registry.py @@ -16,14 +16,14 @@ import os import unittest -from scalecodec.base import ScaleBytes, RuntimeConfigurationObject -from scalecodec.type_registry import load_type_registry_file, load_type_registry_preset +from scalecodec.base import ScaleBytes, RuntimeConfigurationObject # type: ignore[import-untyped] +from scalecodec.type_registry import load_type_registry_file, load_type_registry_preset # type: ignore[import-untyped] from substrateinterface import SubstrateInterface, Keypair, KeypairType from test import settings -class KusamaTypeRegistryTestCase(unittest.TestCase): +class KusamaTypeRegistryTestCase(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): @@ -33,15 +33,15 @@ def setUpClass(cls): type_registry_preset='kusama' ) - def test_type_registry_compatibility(self): + async def test_type_registry_compatibility(self): - for scale_type in self.substrate.get_type_registry(): + for scale_type in await self.substrate.get_type_registry(): obj = self.substrate.runtime_config.get_decoder_class(scale_type) self.assertIsNotNone(obj, '{} not supported'.format(scale_type)) -class PolkadotTypeRegistryTestCase(unittest.TestCase): +class PolkadotTypeRegistryTestCase(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): @@ -51,16 +51,16 @@ def setUpClass(cls): type_registry_preset='polkadot' ) - def test_type_registry_compatibility(self): + async def test_type_registry_compatibility(self): - for scale_type in self.substrate.get_type_registry(): + for scale_type in await self.substrate.get_type_registry(): obj = self.substrate.runtime_config.get_decoder_class(scale_type) self.assertIsNotNone(obj, '{} not supported'.format(scale_type)) -class RococoTypeRegistryTestCase(unittest.TestCase): +class RococoTypeRegistryTestCase(unittest.IsolatedAsyncioTestCase): @classmethod def setUpClass(cls): @@ -70,16 +70,16 @@ def setUpClass(cls): type_registry_preset='rococo' ) - def test_type_registry_compatibility(self): + async def test_type_registry_compatibility(self): - for scale_type in self.substrate.get_type_registry(): + for scale_type in await self.substrate.get_type_registry(): obj = self.substrate.runtime_config.get_decoder_class(scale_type) self.assertIsNotNone(obj, '{} not supported'.format(scale_type)) # -# class DevelopmentTypeRegistryTestCase(unittest.TestCase): +# class DevelopmentTypeRegistryTestCase(unittest.IsolatedAsyncioTestCase): # # @classmethod # def setUpClass(cls): @@ -89,16 +89,16 @@ def test_type_registry_compatibility(self): # type_registry_preset='development' # ) # -# def test_type_registry_compatibility(self): +# async def test_type_registry_compatibility(self): # -# for scale_type in self.substrate.get_type_registry(): +# for scale_type in await self.substrate.get_type_registry(): # # obj = self.substrate.runtime_config.get_decoder_class(scale_type) # # self.assertIsNotNone(obj, '{} not supported'.format(scale_type)) -class ReloadTypeRegistryTestCase(unittest.TestCase): +class ReloadTypeRegistryTestCase(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: self.substrate = SubstrateInterface( @@ -107,11 +107,11 @@ def setUp(self) -> None: type_registry_preset='test' ) - def test_initial_correct_type_local(self): + async def test_initial_correct_type_local(self): decoding_class = self.substrate.runtime_config.type_registry['types']['index'] self.assertEqual(self.substrate.runtime_config.get_decoder_class('u32'), decoding_class) - def test_reloading_use_remote_preset(self): + async def test_reloading_use_remote_preset(self): # Intentionally overwrite type in local preset u32_cls = self.substrate.runtime_config.get_decoder_class('u32') @@ -126,7 +126,7 @@ def test_reloading_use_remote_preset(self): self.assertEqual(u32_cls, self.substrate.runtime_config.get_decoder_class('Index')) - def test_reloading_use_local_preset(self): + async def test_reloading_use_local_preset(self): # Intentionally overwrite type in local preset u32_cls = self.substrate.runtime_config.get_decoder_class('u32') @@ -142,7 +142,7 @@ def test_reloading_use_local_preset(self): self.assertEqual(u32_cls, self.substrate.runtime_config.get_decoder_class('Index')) -class AutodiscoverV14RuntimeTestCase(unittest.TestCase): +class AutodiscoverV14RuntimeTestCase(unittest.IsolatedAsyncioTestCase): runtime_config = None metadata_obj = None metadata_fixture_dict = None @@ -165,7 +165,7 @@ def setUp(self) -> None: class MockedSubstrateInterface(SubstrateInterface): - def rpc_request(self, method, params, result_handler=None): + async def rpc_request(self, method, params, result_handler=None): if method == 'system_chain': return { @@ -174,27 +174,28 @@ def rpc_request(self, method, params, result_handler=None): 'id': self.request_id } - return super().rpc_request(method, params, result_handler) + return await super().rpc_request(method, params, result_handler) self.substrate = MockedSubstrateInterface( url=settings.KUSAMA_NODE_URL ) - def test_type_reg_preset_applied(self): - self.substrate.init_runtime() + async def test_type_reg_preset_applied(self): + await self.substrate.init_runtime() self.assertIsNotNone(self.substrate.runtime_config.get_decoder_class('SpecificTestType')) -class AutodetectAddressTypeTestCase(unittest.TestCase): +class AutodetectAddressTypeTestCase(unittest.IsolatedAsyncioTestCase): - def test_default_substrate_address(self): + async def test_default_substrate_address(self): substrate = SubstrateInterface( url=settings.POLKADOT_NODE_URL, auto_discover=False ) + await substrate.init_props() keypair_alice = Keypair.create_from_uri('//Alice', ss58_format=substrate.ss58_format) - call = substrate.compose_call( + call = await substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -203,18 +204,18 @@ def test_default_substrate_address(self): } ) - extrinsic = substrate.create_signed_extrinsic(call, keypair_alice) + extrinsic = await substrate.create_signed_extrinsic(call, keypair_alice) self.assertEqual(extrinsic.value['address'], f'0x{keypair_alice.public_key.hex()}') - def test_eth_address(self): + async def test_eth_address(self): substrate = SubstrateInterface( url=settings.MOONBEAM_NODE_URL, auto_discover=False ) keypair_alice = Keypair.create_from_mnemonic(Keypair.generate_mnemonic(), crypto_type=KeypairType.ECDSA) - call = substrate.compose_call( + call = await substrate.compose_call( call_module='Balances', call_function='transfer_keep_alive', call_params={ @@ -223,7 +224,7 @@ def test_eth_address(self): } ) - extrinsic = substrate.create_signed_extrinsic(call, keypair_alice) + extrinsic = await substrate.create_signed_extrinsic(call, keypair_alice) self.assertEqual(extrinsic.value['address'], f'0x{keypair_alice.public_key.hex()}') diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..f6ad2d5 --- /dev/null +++ b/uv.lock @@ -0,0 +1,2262 @@ +version = 1 +requires-python = ">=3.9, <4" +resolution-markers = [ + "python_full_version < '3.12'", + "python_full_version >= '3.12'", +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bc/69/2f6d5a019bd02e920a3417689a89887b39ad1e350b562f9955693d900c40/aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", size = 21809 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/d8/120cd0fe3e8530df0539e71ba9683eade12cae103dd7543e50d15f737917/aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572", size = 14742 }, +] + +[[package]] +name = "aiohttp" +version = "3.11.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "async-timeout", marker = "python_full_version < '3.11'" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d5/66/a967a2e9ceab12b6970ca5be3bccc9cf13fed4acfabe2c66de3d75599185/aiohttp-3.11.6.tar.gz", hash = "sha256:fd9f55c1b51ae1c20a1afe7216a64a88d38afee063baa23c7fce03757023c999", size = 7666498 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/1e/3930ea923182595473c4d6838241b5772884d95258b510cc18fcb55ddc72/aiohttp-3.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7510b3ca2275691875ddf072a5b6cd129278d11fe09301add7d292fc8d3432de", size = 706673 }, + { url = "https://files.pythonhosted.org/packages/30/ca/fe72bfd003c3201b6a5535ee4bee9c6f6afcf311c8700cdad5d939dc9dd0/aiohttp-3.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bfab0d2c3380c588fc925168533edb21d3448ad76c3eadc360ff963019161724", size = 466742 }, + { url = "https://files.pythonhosted.org/packages/73/dc/eb23c79a43f5f9344774afaf57858927d0f062febb6c09b2f01ce55d6029/aiohttp-3.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf02dba0f342f3a8228f43fae256aafc21c4bc85bffcf537ce4582e2b1565188", size = 453904 }, + { url = "https://files.pythonhosted.org/packages/69/bf/d7ac318920dc11fce36b45075d3fab0050985f53ac45a026f199fdc1425b/aiohttp-3.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92daedf7221392e7a7984915ca1b0481a94c71457c2f82548414a41d65555e70", size = 1576933 }, + { url = "https://files.pythonhosted.org/packages/95/7f/a66914077d08906aa556ea04458ba49da66bb04b33df1d76ea2005483a46/aiohttp-3.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2274a7876e03429e3218589a6d3611a194bdce08c3f1e19962e23370b47c0313", size = 1630135 }, + { url = "https://files.pythonhosted.org/packages/8b/b8/ec503ad22eb6e6a0bfbb65d52968c641a9fe40369d5cd0d8a39a98da2122/aiohttp-3.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8a2e1eae2d2f62f3660a1591e16e543b2498358593a73b193006fb89ee37abc6", size = 1666637 }, + { url = "https://files.pythonhosted.org/packages/56/20/ba0f2e86b99e162854dcb15a9f8e4d144e0b7c6289cfdd525b875f01d110/aiohttp-3.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:978ec3fb0a42efcd98aae608f58c6cfcececaf0a50b4e86ee3ea0d0a574ab73b", size = 1581015 }, + { url = "https://files.pythonhosted.org/packages/4c/5d/2c2a862b5678ee2e9262ab1f3cf1f6f6ca7dc9a9850d087852cc2bf60e97/aiohttp-3.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51f87b27d9219ed4e202ed8d6f1bb96f829e5eeff18db0d52f592af6de6bdbf", size = 1540268 }, + { url = "https://files.pythonhosted.org/packages/0f/c2/bd9d23fbee7986602b09c406b9eed7b76e42cce0bd12168205252bb3d9ef/aiohttp-3.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:04d1a02a669d26e833c8099992c17f557e3b2fdb7960a0c455d7b1cbcb05121d", size = 1527642 }, + { url = "https://files.pythonhosted.org/packages/ea/1b/4a2d964d9ea2679804961f3d7eaeb57449e0fc193b244e0d25d6a172e848/aiohttp-3.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3679d5fcbc7f1ab518ab4993f12f80afb63933f6afb21b9b272793d398303b98", size = 1533586 }, + { url = "https://files.pythonhosted.org/packages/73/c2/a5075fc0f1fdfbe3d52493241b75de568854ae2f2e868cfe9e954c013fc2/aiohttp-3.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a4b24e03d04893b5c8ec9cd5f2f11dc9c8695c4e2416d2ac2ce6c782e4e5ffa5", size = 1609176 }, + { url = "https://files.pythonhosted.org/packages/4a/ea/154be174020f5713901be31430d31ad6707842af8a04331040c9c813c461/aiohttp-3.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d9abdfd35ecff1c95f270b7606819a0e2de9e06fa86b15d9080de26594cf4c23", size = 1630985 }, + { url = "https://files.pythonhosted.org/packages/8f/8c/2620ab260214bfb2b866ee13b3967fd71af038862d51bb97b4b16dbc10bf/aiohttp-3.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8b5c3e7928a0ad80887a5eba1c1da1830512ddfe7394d805badda45c03db3109", size = 1564450 }, + { url = "https://files.pythonhosted.org/packages/af/1d/605cd586f84fd736dc0a74f3677a13304ce1780492b7b6b40aafe5810273/aiohttp-3.11.6-cp310-cp310-win32.whl", hash = "sha256:913dd9e9378f3c38aeb5c4fb2b8383d6490bc43f3b427ae79f2870651ae08f22", size = 414949 }, + { url = "https://files.pythonhosted.org/packages/be/c7/0f5d1d04a2307ca8f36fa512c1c66e732351058c761e72e366c1bc24d0cb/aiohttp-3.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:4ac26d482c2000c3a59bf757a77adc972828c9d4177b4bd432a46ba682ca7271", size = 440421 }, + { url = "https://files.pythonhosted.org/packages/70/fe/32fc7c6e0a0f2f5b319b144aa7b83e631f9dd7c4b2378ccd4a4f89e273a8/aiohttp-3.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:26ac4c960ea8debf557357a172b3ef201f2236a462aefa1bc17683a75483e518", size = 706721 }, + { url = "https://files.pythonhosted.org/packages/bf/5d/5d7ce161704f49cbc71d6131a49df436652bbe487bc5c161e00d9c29dd2c/aiohttp-3.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8b1f13ebc99fb98c7c13057b748f05224ccc36d17dee18136c695ef23faaf4ff", size = 466586 }, + { url = "https://files.pythonhosted.org/packages/60/db/420563f259d98056a2968fbe54ed9e8fd5b8593dc57fa141a9fe79480a49/aiohttp-3.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4679f1a47516189fab1774f7e45a6c7cac916224c91f5f94676f18d0b64ab134", size = 454116 }, + { url = "https://files.pythonhosted.org/packages/c3/54/8c078304a44bcd456c54b9a207a1d9f2d1ede71190da05289c5e6fbe879f/aiohttp-3.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74491fdb3d140ff561ea2128cb7af9ba0a360067ee91074af899c9614f88a18f", size = 1685120 }, + { url = "https://files.pythonhosted.org/packages/40/79/8bcb755f6f18d25cb6d6acbb4fbf42364cc7d3e7108b200b377a1dfd5695/aiohttp-3.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f51e1a90412d387e62aa2d243998c5eddb71373b199d811e6ed862a9f34f9758", size = 1741282 }, + { url = "https://files.pythonhosted.org/packages/c8/29/a67701b6e13695085ec58e6fa77afad9a69e6303d72a711cb4044ef6f7a1/aiohttp-3.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72ab89510511c3bb703d0bb5504787b11e0ed8be928ed2a7cf1cda9280628430", size = 1781005 }, + { url = "https://files.pythonhosted.org/packages/b0/08/342b8e456179d74948fb9389c9339bc146ad03ca85a48acd193c28b4a52d/aiohttp-3.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6681c9e046d99646e8059266688374a063da85b2e4c0ebfa078cda414905d080", size = 1676880 }, + { url = "https://files.pythonhosted.org/packages/41/44/5051b093c50b0cfc0ca7490057a431e43ec7758b09b87bcb23b97899ae9a/aiohttp-3.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a17f8a6d3ab72cbbd137e494d1a23fbd3ea973db39587941f32901bb3c5c350", size = 1619837 }, + { url = "https://files.pythonhosted.org/packages/a1/6d/37076f6413bb1a0f2a78075556207a3f1a86934850e34200aa6def13aa4b/aiohttp-3.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:867affc7612a314b95f74d93aac550ce0909bc6f0b6c658cc856890f4d326542", size = 1643338 }, + { url = "https://files.pythonhosted.org/packages/0f/f8/007e9e84fc455b08123e91826385e0d002da6a48a697b407a37f5fa2fbd2/aiohttp-3.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:00d894ebd609d5a423acef885bd61e7f6a972153f99c5b3ea45fc01fe909196c", size = 1647471 }, + { url = "https://files.pythonhosted.org/packages/96/b6/bef4929fd4890a80606b03a83c1df4564a2d4a700c01ea6940ac1af4ab99/aiohttp-3.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:614c87be9d0d64477d1e4b663bdc5d1534fc0a7ebd23fb08347ab9fd5fe20fd7", size = 1731045 }, + { url = "https://files.pythonhosted.org/packages/ed/e3/9014a5d2186b11e3c1a5a17db90026791ccb43fe587e66b4ef13679d657d/aiohttp-3.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:533ed46cf772f28f3bffae81c0573d916a64dee590b5dfaa3f3d11491da05b95", size = 1751570 }, + { url = "https://files.pythonhosted.org/packages/e6/34/11c242462feab715323100fecb93ca54dbcc56c6b5250b590999e294e0b0/aiohttp-3.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:589884cfbc09813afb1454816b45677e983442e146183143f988f7f5a040791a", size = 1692751 }, + { url = "https://files.pythonhosted.org/packages/bc/40/97ef6c13269a220aa2ffb1df5c5d5a5602830fc6a6c68ec127f4214a960e/aiohttp-3.11.6-cp311-cp311-win32.whl", hash = "sha256:1da63633ba921669eec3d7e080459d4ceb663752b3dafb2f31f18edd248d2170", size = 414827 }, + { url = "https://files.pythonhosted.org/packages/11/1f/d65326babeaa161a58b92a472af2c9098f54a5bff0b6a22711468d5ffce1/aiohttp-3.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:d778ddda09622e7d83095cc8051698a0084c155a1474bfee9bac27d8613dbc31", size = 440844 }, + { url = "https://files.pythonhosted.org/packages/6e/0a/e0afd75b198c870b913c085534f66bd1681e8f0a41f69d05a55f372c0096/aiohttp-3.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:943a952df105a5305257984e7a1f5c2d0fd8564ff33647693c4d07eb2315446d", size = 702247 }, + { url = "https://files.pythonhosted.org/packages/f5/50/5793686d24901d07f4e66557487aff24d319afc2b02476cdcdf3a670d371/aiohttp-3.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d24ec28b7658970a1f1d98608d67f88376c7e503d9d45ff2ba1949c09f2b358c", size = 461930 }, + { url = "https://files.pythonhosted.org/packages/ec/1e/5cb24d35a6e8e5701c892c5688e8d3f8604e8e9ffa4b8e960c96a4b61aff/aiohttp-3.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6720e809a660fdb9bec7c168c582e11cfedce339af0a5ca847a5d5b588dce826", size = 454378 }, + { url = "https://files.pythonhosted.org/packages/9f/ea/e5e4cbceab6048328ee0d92df068e30b063160b44126d100e3a616546610/aiohttp-3.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4252d30da0ada6e6841b325869c7ef5104b488e8dd57ec439892abbb8d7b3615", size = 1678311 }, + { url = "https://files.pythonhosted.org/packages/f4/48/5def805c865153b99f924058f8f62257046834d643c7c389ca63431c7edf/aiohttp-3.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f65f43ff01b238aa0b5c47962c83830a49577efe31bd37c1400c3d11d8a32835", size = 1734568 }, + { url = "https://files.pythonhosted.org/packages/a1/63/b8edb2603f190804f3ab2d047dc2b2f459d406a31b79c283471a645fe8d0/aiohttp-3.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4dc5933f6c9b26404444d36babb650664f984b8e5fa0694540e7b7315d11a4ff", size = 1788696 }, + { url = "https://files.pythonhosted.org/packages/95/fa/64f226ad78bd64f28ad4076a000b1b07eb4c00ce8e5c6d969fd062716943/aiohttp-3.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5bf546ba0c029dfffc718c4b67748687fd4f341b07b7c8f1719d6a3a46164798", size = 1687186 }, + { url = "https://files.pythonhosted.org/packages/5c/09/146c939383178f6f1b98b5f7237440f2ec11a389f9af6f5138417dd2d782/aiohttp-3.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c351d05bbeae30c088009c0bb3b17dda04fd854f91cc6196c448349cc98f71c3", size = 1618410 }, + { url = "https://files.pythonhosted.org/packages/86/35/a161883bb7cab653f0ed5839a65729f9310bd576ff053de05bc1baf3d782/aiohttp-3.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:10499079b063576fad1597898de3f9c0a2ce617c19cc7cd6b62fdcff6b408bf7", size = 1635584 }, + { url = "https://files.pythonhosted.org/packages/32/0b/e84648caec84302defc6b9eba212b0a80a8bd13a38036182067339ba1a59/aiohttp-3.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:442ee82eda47dd59798d6866ce020fb8d02ea31ac9ac82b3d719ed349e6a9d52", size = 1649399 }, + { url = "https://files.pythonhosted.org/packages/b1/20/6f72d893d9df912cad2caf0506b36b08e4525c59e0c95b0a5a361cac0d5c/aiohttp-3.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:86fce9127bc317119b34786d9e9ae8af4508a103158828a535f56d201da6ab19", size = 1697349 }, + { url = "https://files.pythonhosted.org/packages/c5/56/c063555109a33465c488320b16433d355d9afaa2cfaa9d2b54cc86c5e2ea/aiohttp-3.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:973d26a5537ce5d050302eb3cd876457451745b1da0624cbb483217970e12567", size = 1728236 }, + { url = "https://files.pythonhosted.org/packages/1b/26/50ec0670fe6a87311678c7e40839868c49b3500f74c05abe658ddaf241ab/aiohttp-3.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:532b8f038a4e001137d3600cea5d3439d1881df41bdf44d0f9651264d562fdf0", size = 1688531 }, + { url = "https://files.pythonhosted.org/packages/50/71/4f17ceeb100611590a1d36129ee7a792744b30825e1e22cc6161b8a32977/aiohttp-3.11.6-cp312-cp312-win32.whl", hash = "sha256:4863c59f748dbe147da82b389931f2a676aebc9d3419813ed5ca32d057c9cb32", size = 409894 }, + { url = "https://files.pythonhosted.org/packages/9b/93/e170e36c43990e07340f24477daa3674720b802d85a0d21f0040721f8116/aiohttp-3.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:5d7f481f82c18ac1f7986e31ba6eea9be8b2e2c86f1ef035b6866179b6c5dd68", size = 436416 }, + { url = "https://files.pythonhosted.org/packages/4b/75/5a0946eb3d0b006399f5244e0ffef9da1a0b05a1d8800373696d132dc87a/aiohttp-3.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:40f502350496ba4c6820816d3164f8a0297b9aa4e95d910da31beb189866a9df", size = 695722 }, + { url = "https://files.pythonhosted.org/packages/37/dc/099c4f3dc41be7f24de60af2b6795bf2a821533666dca6ff47dae14627b8/aiohttp-3.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9072669b0bffb40f1f6977d0b5e8a296edc964f9cefca3a18e68649c214d0ce3", size = 458501 }, + { url = "https://files.pythonhosted.org/packages/1e/ac/ad5b5d5a871290382660d0a8dc0bd0285fc98da169f5ed4d1a7cf735ff82/aiohttp-3.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:518160ecf4e6ffd61715bc9173da0925fcce44ae6c7ca3d3f098fe42585370fb", size = 451387 }, + { url = "https://files.pythonhosted.org/packages/8d/b3/982bf01e6d9e1874ec34f9871650037f409711a319e8374a206ab850629f/aiohttp-3.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f69cc1b45115ac44795b63529aa5caa9674be057f11271f65474127b24fc1ce6", size = 1662290 }, + { url = "https://files.pythonhosted.org/packages/f4/05/2102ae02f9310cc2c777f4355f12a2139be9fcb0469c60f52d87b04c98ba/aiohttp-3.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6be90a6beced41653bda34afc891617c6d9e8276eef9c183f029f851f0a3c3d", size = 1713486 }, + { url = "https://files.pythonhosted.org/packages/df/c0/aa0b58ef44b12ba5fd8cf61d38e4b69e083ef6ad5cc2dec51c201a594151/aiohttp-3.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00c22fe2486308770d22ef86242101d7b0f1e1093ce178f2358f860e5149a551", size = 1769864 }, + { url = "https://files.pythonhosted.org/packages/b2/76/fc2d851cdd737fdb0bb207c82b7ecf3ddadbb9dbeadf9eff19fcb8205884/aiohttp-3.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2607ebb783e3aeefa017ec8f34b506a727e6b6ab2c4b037d65f0bc7151f4430a", size = 1673204 }, + { url = "https://files.pythonhosted.org/packages/84/76/8afa5d952d2b7f1e899849b36145e710d443edecf70b4be4c5ade686c3bb/aiohttp-3.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f761d6819870c2a8537f75f3e2fc610b163150cefa01f9f623945840f601b2c", size = 1600101 }, + { url = "https://files.pythonhosted.org/packages/ab/84/a0a5fd9e51f79bdbda8ed25a7ff864bd4edc7afda5bc07bfa8cdb5ebc92f/aiohttp-3.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e44d1bc6c88f5234115011842219ba27698a5f2deee245c963b180080572aaa2", size = 1617053 }, + { url = "https://files.pythonhosted.org/packages/35/91/43278170a636a53bb6b40a862ca60b65bb1007664b9a7f2a01fadea70e8c/aiohttp-3.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7e0cb6a1b1f499cb2aa0bab1c9f2169ad6913c735b7447e058e0c29c9e51c0b5", size = 1617185 }, + { url = "https://files.pythonhosted.org/packages/a0/89/80a6f8661627ad6eba5d03a351a6af56ee7236bddf27b4a6ebae79b24e4d/aiohttp-3.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a76b4d4ca34254dca066acff2120811e2a8183997c135fcafa558280f2cc53f3", size = 1684465 }, + { url = "https://files.pythonhosted.org/packages/85/5e/e27cbafe135840a9855ef2a60a413f652e44fa707ea3b272eb7870b853cc/aiohttp-3.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:69051c1e45fb18c0ae4d39a075532ff0b015982e7997f19eb5932eb4a3e05c17", size = 1714956 }, + { url = "https://files.pythonhosted.org/packages/d7/c1/dbb98a399c776a0b5bd3f825b26abb1ff9648b2437e44cda5d04517a8ea9/aiohttp-3.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:aff2ed18274c0bfe0c1d772781c87d5ca97ae50f439729007cec9644ee9b15fe", size = 1670542 }, + { url = "https://files.pythonhosted.org/packages/dd/a0/418c1474806c051ee95e1f600302f72f7a5d1f7705b694ac2f5a03937b31/aiohttp-3.11.6-cp313-cp313-win32.whl", hash = "sha256:2fbea25f2d44df809a46414a8baafa5f179d9dda7e60717f07bded56300589b3", size = 408688 }, + { url = "https://files.pythonhosted.org/packages/30/42/0567f9707e6016040567a715c20dae743b70b413889f4d3ae18a4b45e4bb/aiohttp-3.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:f77bc29a465c0f9f6573d1abe656d385fa673e34efe615bd4acc50899280ee47", size = 434758 }, + { url = "https://files.pythonhosted.org/packages/19/f5/4ff6c65f6829dcf82355473b099747a8ac52b7733dd5cb2d81b9ffc15a7a/aiohttp-3.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:de6123b298d17bca9e53581f50a275b36e10d98e8137eb743ce69ee766dbdfe9", size = 707586 }, + { url = "https://files.pythonhosted.org/packages/d7/62/4b40db802c60d4400d2ea2665b7389a61e0c303ee3d024f37bd957b2c407/aiohttp-3.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a10200f705f4fff00e148b7f41e5d1d929c7cd4ac523c659171a0ea8284cd6fb", size = 467193 }, + { url = "https://files.pythonhosted.org/packages/cc/da/1b47bb849643c028ee5a1a1fa618e6c9fa96ce5a92e1e12f1e9fb1c51ec9/aiohttp-3.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b7776ef6901b54dd557128d96c71e412eec0c39ebc07567e405ac98737995aad", size = 454417 }, + { url = "https://files.pythonhosted.org/packages/b3/28/aef297b609bdc47b4e66be2c01ecc8d328e09d36ada79469a0feeb98a495/aiohttp-3.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e5c2a55583cd91936baf73d223807bb93ace6eb1fe54424782690f2707162ab", size = 1578799 }, + { url = "https://files.pythonhosted.org/packages/0d/21/f2242fce0da1d061ec6e307300b1368be457b20dcd70b8751dbf1cc0845e/aiohttp-3.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b032bd6cf7422583bf44f233f4a1489fee53c6d35920123a208adc54e2aba41e", size = 1632866 }, + { url = "https://files.pythonhosted.org/packages/2a/c6/8b31cfa5359c148502f18e4f491ddb3dbde7a831e7a0ce361cb0e19d1e09/aiohttp-3.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fe2d99acbc5cf606f75d7347bf3a027c24c27bc052d470fb156f4cfcea5739", size = 1669942 }, + { url = "https://files.pythonhosted.org/packages/8c/69/b9393c41ff979d9c252808c4722301c029659371155a00af209629a6bc88/aiohttp-3.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84a79c366375c2250934d1238abe5d5ea7754c823a1c7df0c52bf0a2bfded6a9", size = 1584254 }, + { url = "https://files.pythonhosted.org/packages/49/c4/963bdf051cf4bc7058212de9f8ea32184f656e40b30b7e51032e050b17d7/aiohttp-3.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c33cbbe97dc94a34d1295a7bb68f82727bcbff2b284f73ae7e58ecc05903da97", size = 1539682 }, + { url = "https://files.pythonhosted.org/packages/f8/0c/ed272915b0f3a908750fa016e8e16d6927b875413f60cbbc80ccd69fa058/aiohttp-3.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:19e4fb9ac727834b003338dcdd27dcfe0de4fb44082b01b34ed0ab67c3469fc9", size = 1524602 }, + { url = "https://files.pythonhosted.org/packages/6a/22/25ea16621f8fa9d4ed3298c0e810a039d26fe640c4bd4dadc7f75ca35867/aiohttp-3.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a97f6b2afbe1d27220c0c14ea978e09fb4868f462ef3d56d810d206bd2e057a2", size = 1533639 }, + { url = "https://files.pythonhosted.org/packages/7c/82/a9ab0fa363927a95e300a99ad37ec542cd6450831852661d26ffa604814c/aiohttp-3.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c3f7afeea03a9bc49be6053dfd30809cd442cc12627d6ca08babd1c1f9e04ccf", size = 1608721 }, + { url = "https://files.pythonhosted.org/packages/20/48/9c31d02cb3b65f656c7fb833edd0c9c0d67fdd7a1e83fe730cf7ca1ec54b/aiohttp-3.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0d10967600ce5bb69ddcb3e18d84b278efb5199d8b24c3c71a4959c2f08acfd0", size = 1627181 }, + { url = "https://files.pythonhosted.org/packages/83/c0/39589e12981d47e50b824bf62956e44214135136ae1465833fbe7b8efc6d/aiohttp-3.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:60f2f631b9fe7aa321fa0f0ff3f5d8b9f7f9b72afd4eecef61c33cf1cfea5d58", size = 1562402 }, + { url = "https://files.pythonhosted.org/packages/20/1f/c5e3e0a75ca4b67d84384169d85591d49cf035cd1dde9dfc356be6f44e7a/aiohttp-3.11.6-cp39-cp39-win32.whl", hash = "sha256:4d2b75333deb5c5f61bac5a48bba3dbc142eebbd3947d98788b6ef9cc48628ae", size = 415233 }, + { url = "https://files.pythonhosted.org/packages/eb/78/3e5c65c991aba782588aacf042bfbd246ab429dbd333679d10776e51c973/aiohttp-3.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:8908c235421972a2e02abcef87d16084aabfe825d14cc9a1debd609b3cfffbea", size = 440654 }, +] + +[[package]] +name = "aiosignal" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, +] + +[[package]] +name = "async-timeout" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 }, +] + +[[package]] +name = "attrs" +version = "24.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, +] + +[[package]] +name = "babel" +version = "2.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/74/f1bc80f23eeba13393b7222b11d95ca3af2c1e28edca18af487137eefed9/babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316", size = 9348104 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", size = 9587599 }, +] + +[[package]] +name = "base58" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/45/8ae61209bb9015f516102fa559a2914178da1d5868428bd86a1b4421141d/base58-2.1.1.tar.gz", hash = "sha256:c5d0cb3f5b6e81e8e35da5754388ddcc6d0d14b6c6a132cb93d69ed580a7278c", size = 6528 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/45/ec96b29162a402fc4c1c5512d114d7b3787b9d1c2ec241d9568b4816ee23/base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2", size = 5621 }, +] + +[[package]] +name = "black" +version = "24.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/f3/465c0eb5cddf7dbbfe1fecd9b875d1dcf51b88923cd2c1d7e9ab95c6336b/black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812", size = 1623211 }, + { url = "https://files.pythonhosted.org/packages/df/57/b6d2da7d200773fdfcc224ffb87052cf283cec4d7102fab450b4a05996d8/black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea", size = 1457139 }, + { url = "https://files.pythonhosted.org/packages/6e/c5/9023b7673904a5188f9be81f5e129fff69f51f5515655fbd1d5a4e80a47b/black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f", size = 1753774 }, + { url = "https://files.pythonhosted.org/packages/e1/32/df7f18bd0e724e0d9748829765455d6643ec847b3f87e77456fc99d0edab/black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e", size = 1414209 }, + { url = "https://files.pythonhosted.org/packages/c2/cc/7496bb63a9b06a954d3d0ac9fe7a73f3bf1cd92d7a58877c27f4ad1e9d41/black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", size = 1607468 }, + { url = "https://files.pythonhosted.org/packages/2b/e3/69a738fb5ba18b5422f50b4f143544c664d7da40f09c13969b2fd52900e0/black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", size = 1437270 }, + { url = "https://files.pythonhosted.org/packages/c9/9b/2db8045b45844665c720dcfe292fdaf2e49825810c0103e1191515fc101a/black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", size = 1737061 }, + { url = "https://files.pythonhosted.org/packages/a3/95/17d4a09a5be5f8c65aa4a361444d95edc45def0de887810f508d3f65db7a/black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", size = 1423293 }, + { url = "https://files.pythonhosted.org/packages/90/04/bf74c71f592bcd761610bbf67e23e6a3cff824780761f536512437f1e655/black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", size = 1644256 }, + { url = "https://files.pythonhosted.org/packages/4c/ea/a77bab4cf1887f4b2e0bce5516ea0b3ff7d04ba96af21d65024629afedb6/black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", size = 1448534 }, + { url = "https://files.pythonhosted.org/packages/4e/3e/443ef8bc1fbda78e61f79157f303893f3fddf19ca3c8989b163eb3469a12/black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", size = 1761892 }, + { url = "https://files.pythonhosted.org/packages/52/93/eac95ff229049a6901bc84fec6908a5124b8a0b7c26ea766b3b8a5debd22/black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", size = 1434796 }, + { url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986 }, + { url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085 }, + { url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928 }, + { url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875 }, + { url = "https://files.pythonhosted.org/packages/fe/02/f408c804e0ee78c367dcea0a01aedde4f1712af93b8b6e60df981e0228c7/black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd", size = 1622516 }, + { url = "https://files.pythonhosted.org/packages/f8/b9/9b706ed2f55bfb28b436225a9c57da35990c9005b90b8c91f03924454ad7/black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f", size = 1456181 }, + { url = "https://files.pythonhosted.org/packages/0a/1c/314d7f17434a5375682ad097f6f4cc0e3f414f3c95a9b1bb4df14a0f11f9/black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800", size = 1752801 }, + { url = "https://files.pythonhosted.org/packages/39/a7/20e5cd9237d28ad0b31438de5d9f01c8b99814576f4c0cda1edd62caf4b0/black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7", size = 1413626 }, + { url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898 }, +] + +[[package]] +name = "certifi" +version = "2024.8.30" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191 }, + { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592 }, + { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024 }, + { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188 }, + { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571 }, + { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687 }, + { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211 }, + { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325 }, + { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784 }, + { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564 }, + { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804 }, + { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299 }, + { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, + { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, + { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, + { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, + { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, + { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, + { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, + { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, + { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, + { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, + { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, + { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, + { url = "https://files.pythonhosted.org/packages/b9/ea/8bb50596b8ffbc49ddd7a1ad305035daa770202a6b782fc164647c2673ad/cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", size = 182220 }, + { url = "https://files.pythonhosted.org/packages/ae/11/e77c8cd24f58285a82c23af484cf5b124a376b32644e445960d1a4654c3a/cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", size = 178605 }, + { url = "https://files.pythonhosted.org/packages/ed/65/25a8dc32c53bf5b7b6c2686b42ae2ad58743f7ff644844af7cdb29b49361/cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", size = 424910 }, + { url = "https://files.pythonhosted.org/packages/42/7a/9d086fab7c66bd7c4d0f27c57a1b6b068ced810afc498cc8c49e0088661c/cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", size = 447200 }, + { url = "https://files.pythonhosted.org/packages/da/63/1785ced118ce92a993b0ec9e0d0ac8dc3e5dbfbcaa81135be56c69cabbb6/cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", size = 454565 }, + { url = "https://files.pythonhosted.org/packages/74/06/90b8a44abf3556599cdec107f7290277ae8901a58f75e6fe8f970cd72418/cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", size = 435635 }, + { url = "https://files.pythonhosted.org/packages/bd/62/a1f468e5708a70b1d86ead5bab5520861d9c7eacce4a885ded9faa7729c3/cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", size = 445218 }, + { url = "https://files.pythonhosted.org/packages/5b/95/b34462f3ccb09c2594aa782d90a90b045de4ff1f70148ee79c69d37a0a5a/cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", size = 460486 }, + { url = "https://files.pythonhosted.org/packages/fc/fc/a1e4bebd8d680febd29cf6c8a40067182b64f00c7d105f8f26b5bc54317b/cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", size = 437911 }, + { url = "https://files.pythonhosted.org/packages/e6/c3/21cab7a6154b6a5ea330ae80de386e7665254835b9e98ecc1340b3a7de9a/cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", size = 460632 }, + { url = "https://files.pythonhosted.org/packages/cb/b5/fd9f8b5a84010ca169ee49f4e4ad6f8c05f4e3545b72ee041dbbcb159882/cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", size = 171820 }, + { url = "https://files.pythonhosted.org/packages/8c/52/b08750ce0bce45c143e1b5d7357ee8c55341b52bdef4b0f081af1eb248c2/cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", size = 181290 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/8b/825cc84cf13a28bfbcba7c416ec22bf85a9584971be15b21dd8300c65b7f/charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", size = 196363 }, + { url = "https://files.pythonhosted.org/packages/23/81/d7eef6a99e42c77f444fdd7bc894b0ceca6c3a95c51239e74a722039521c/charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", size = 125639 }, + { url = "https://files.pythonhosted.org/packages/21/67/b4564d81f48042f520c948abac7079356e94b30cb8ffb22e747532cf469d/charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", size = 120451 }, + { url = "https://files.pythonhosted.org/packages/c2/72/12a7f0943dd71fb5b4e7b55c41327ac0a1663046a868ee4d0d8e9c369b85/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", size = 140041 }, + { url = "https://files.pythonhosted.org/packages/67/56/fa28c2c3e31217c4c52158537a2cf5d98a6c1e89d31faf476c89391cd16b/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", size = 150333 }, + { url = "https://files.pythonhosted.org/packages/f9/d2/466a9be1f32d89eb1554cf84073a5ed9262047acee1ab39cbaefc19635d2/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", size = 142921 }, + { url = "https://files.pythonhosted.org/packages/f8/01/344ec40cf5d85c1da3c1f57566c59e0c9b56bcc5566c08804a95a6cc8257/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", size = 144785 }, + { url = "https://files.pythonhosted.org/packages/73/8b/2102692cb6d7e9f03b9a33a710e0164cadfce312872e3efc7cfe22ed26b4/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", size = 146631 }, + { url = "https://files.pythonhosted.org/packages/d8/96/cc2c1b5d994119ce9f088a9a0c3ebd489d360a2eb058e2c8049f27092847/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", size = 140867 }, + { url = "https://files.pythonhosted.org/packages/c9/27/cde291783715b8ec30a61c810d0120411844bc4c23b50189b81188b273db/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", size = 149273 }, + { url = "https://files.pythonhosted.org/packages/3a/a4/8633b0fc1a2d1834d5393dafecce4a1cc56727bfd82b4dc18fc92f0d3cc3/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", size = 152437 }, + { url = "https://files.pythonhosted.org/packages/64/ea/69af161062166b5975ccbb0961fd2384853190c70786f288684490913bf5/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", size = 150087 }, + { url = "https://files.pythonhosted.org/packages/3b/fd/e60a9d9fd967f4ad5a92810138192f825d77b4fa2a557990fd575a47695b/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", size = 145142 }, + { url = "https://files.pythonhosted.org/packages/6d/02/8cb0988a1e49ac9ce2eed1e07b77ff118f2923e9ebd0ede41ba85f2dcb04/charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", size = 94701 }, + { url = "https://files.pythonhosted.org/packages/d6/20/f1d4670a8a723c46be695dff449d86d6092916f9e99c53051954ee33a1bc/charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", size = 102191 }, + { url = "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", size = 193339 }, + { url = "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", size = 124366 }, + { url = "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", size = 118874 }, + { url = "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", size = 138243 }, + { url = "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", size = 148676 }, + { url = "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", size = 141289 }, + { url = "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", size = 142585 }, + { url = "https://files.pythonhosted.org/packages/3b/a0/a68980ab8a1f45a36d9745d35049c1af57d27255eff8c907e3add84cf68f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", size = 144408 }, + { url = "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", size = 139076 }, + { url = "https://files.pythonhosted.org/packages/fb/9d/9c13753a5a6e0db4a0a6edb1cef7aee39859177b64e1a1e748a6e3ba62c2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", size = 146874 }, + { url = "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", size = 150871 }, + { url = "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", size = 148546 }, + { url = "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", size = 143048 }, + { url = "https://files.pythonhosted.org/packages/01/f8/38842422988b795220eb8038745d27a675ce066e2ada79516c118f291f07/charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", size = 94389 }, + { url = "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", size = 101752 }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445 }, + { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275 }, + { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020 }, + { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128 }, + { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277 }, + { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174 }, + { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838 }, + { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149 }, + { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043 }, + { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229 }, + { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556 }, + { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772 }, + { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 }, + { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 }, + { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 }, + { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 }, + { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 }, + { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 }, + { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 }, + { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 }, + { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 }, + { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 }, + { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 }, + { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 }, + { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 }, + { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 }, + { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 }, + { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, + { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, + { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, + { url = "https://files.pythonhosted.org/packages/54/2f/28659eee7f5d003e0f5a3b572765bf76d6e0fe6601ab1f1b1dd4cba7e4f1/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", size = 196326 }, + { url = "https://files.pythonhosted.org/packages/d1/18/92869d5c0057baa973a3ee2af71573be7b084b3c3d428fe6463ce71167f8/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", size = 125614 }, + { url = "https://files.pythonhosted.org/packages/d6/27/327904c5a54a7796bb9f36810ec4173d2df5d88b401d2b95ef53111d214e/charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", size = 120450 }, + { url = "https://files.pythonhosted.org/packages/a4/23/65af317914a0308495133b2d654cf67b11bbd6ca16637c4e8a38f80a5a69/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", size = 140135 }, + { url = "https://files.pythonhosted.org/packages/f2/41/6190102ad521a8aa888519bb014a74251ac4586cde9b38e790901684f9ab/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", size = 150413 }, + { url = "https://files.pythonhosted.org/packages/7b/ab/f47b0159a69eab9bd915591106859f49670c75f9a19082505ff16f50efc0/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", size = 142992 }, + { url = "https://files.pythonhosted.org/packages/28/89/60f51ad71f63aaaa7e51a2a2ad37919985a341a1d267070f212cdf6c2d22/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", size = 144871 }, + { url = "https://files.pythonhosted.org/packages/0c/48/0050550275fea585a6e24460b42465020b53375017d8596c96be57bfabca/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", size = 146756 }, + { url = "https://files.pythonhosted.org/packages/dc/b5/47f8ee91455946f745e6c9ddbb0f8f50314d2416dd922b213e7d5551ad09/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", size = 141034 }, + { url = "https://files.pythonhosted.org/packages/84/79/5c731059ebab43e80bf61fa51666b9b18167974b82004f18c76378ed31a3/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", size = 149434 }, + { url = "https://files.pythonhosted.org/packages/ca/f3/0719cd09fc4dc42066f239cb3c48ced17fc3316afca3e2a30a4756fe49ab/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", size = 152443 }, + { url = "https://files.pythonhosted.org/packages/f7/0e/c6357297f1157c8e8227ff337e93fd0a90e498e3d6ab96b2782204ecae48/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", size = 150294 }, + { url = "https://files.pythonhosted.org/packages/54/9a/acfa96dc4ea8c928040b15822b59d0863d6e1757fba8bd7de3dc4f761c13/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", size = 145314 }, + { url = "https://files.pythonhosted.org/packages/73/1c/b10a63032eaebb8d7bcb8544f12f063f41f5f463778ac61da15d9985e8b6/charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", size = 94724 }, + { url = "https://files.pythonhosted.org/packages/c5/77/3a78bf28bfaa0863f9cfef278dbeadf55efe064eafff8c7c424ae3c4c1bf/charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", size = 102159 }, + { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, +] + +[[package]] +name = "click" +version = "8.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, +] + +[[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 = "coverage" +version = "7.6.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/68/26895f8b068e384b1ec9ab122565b913b735e6b4c618b3d265a280607edc/coverage-7.6.7.tar.gz", hash = "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24", size = 799938 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/c9/84898713e61208ddbe71b991d8f311d9ca175629ce5f1a46018acc643572/coverage-7.6.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e", size = 206875 }, + { url = "https://files.pythonhosted.org/packages/f0/69/7dfd65f0e284617f72d974f6dfedc7bc16f86172e5bc6ebc8b63430263f3/coverage-7.6.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45", size = 207307 }, + { url = "https://files.pythonhosted.org/packages/d1/ce/6e356b2bc751bdaadd77c714336b98ec45ccaf0cfe085b6b25d34f7cceb8/coverage-7.6.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1", size = 235744 }, + { url = "https://files.pythonhosted.org/packages/35/49/a7ab3d5a507d32344994cab856784e8d603c0b698070f7667c3ae41e8e50/coverage-7.6.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c", size = 233645 }, + { url = "https://files.pythonhosted.org/packages/bd/41/de07328d2e79916fcc6cd53a5a1d18d163483519ab95f7f60fe15276811c/coverage-7.6.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2", size = 234807 }, + { url = "https://files.pythonhosted.org/packages/e4/cc/2a669319b1295e0c52e8cfbbb163b32188b62f3b0bbe7014ef402b24b7cf/coverage-7.6.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06", size = 233902 }, + { url = "https://files.pythonhosted.org/packages/68/71/a1bb90cb177358a2d364b3968a2069225f614d6824c3d959dee688ca0902/coverage-7.6.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777", size = 232363 }, + { url = "https://files.pythonhosted.org/packages/eb/dc/87551219d3437214523d1c7de0a717bead7a3369ed9bae05a7fd2854476f/coverage-7.6.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314", size = 233493 }, + { url = "https://files.pythonhosted.org/packages/ca/a4/d74ae3a3fb9e55fe5d9b811ce68a6bd8df3ae0a92c336acbc00075bc24fa/coverage-7.6.7-cp310-cp310-win32.whl", hash = "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a", size = 209593 }, + { url = "https://files.pythonhosted.org/packages/77/cb/7984c4d0404e8fcc4ada226b240965ef056e7a20e61a18c9038bf88e7624/coverage-7.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163", size = 210398 }, + { url = "https://files.pythonhosted.org/packages/c6/d7/1bf7bb0943237149ad01977190ac5c2e17add1f4fe7cabc06401682137f6/coverage-7.6.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469", size = 206979 }, + { url = "https://files.pythonhosted.org/packages/83/eb/863b2cd654353b94c6ad834008df813424bf3e8f110e5f655fe5dc4c423b/coverage-7.6.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99", size = 207431 }, + { url = "https://files.pythonhosted.org/packages/35/c9/d7a02a9654c41174fb99402c0fbd9583d0d2cb8714e7f948117fa7f919c4/coverage-7.6.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec", size = 239368 }, + { url = "https://files.pythonhosted.org/packages/11/64/6c43a0ec43e5ddc5e09b0b589e3fd31def05fc463920d084e5af35fe527d/coverage-7.6.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b", size = 236769 }, + { url = "https://files.pythonhosted.org/packages/1c/dc/e77d98ae433c556c29328712a07fed0e6d159a63b2ec81039ce0a13a24a3/coverage-7.6.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a", size = 238634 }, + { url = "https://files.pythonhosted.org/packages/cc/84/50df3a8426d686057496171b4ccdb64528dacc4f42e94dceb7de3c598a69/coverage-7.6.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b", size = 237562 }, + { url = "https://files.pythonhosted.org/packages/2e/0f/9560196247574c1ccdab64cb923d69119fd5abd5b3db28d601ab2b452861/coverage-7.6.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d", size = 236197 }, + { url = "https://files.pythonhosted.org/packages/df/14/38b7c081e86e845df1867143ddb6e05bf8395f60ab3923c023a56d97cca1/coverage-7.6.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4", size = 236970 }, + { url = "https://files.pythonhosted.org/packages/8b/f3/af34f814ca3814f798878ae368b638edb91298595470614f5265f3f416fa/coverage-7.6.7-cp311-cp311-win32.whl", hash = "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2", size = 209557 }, + { url = "https://files.pythonhosted.org/packages/5a/9e/5d1080d83d752873bd9dedea5524c0f5fe68a3d5e1e58c590865bd724591/coverage-7.6.7-cp311-cp311-win_amd64.whl", hash = "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f", size = 210402 }, + { url = "https://files.pythonhosted.org/packages/84/30/30e9df650b9038962c62d900b093a17414d5b43b4d07d47b8698d9e7ce26/coverage-7.6.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9", size = 207172 }, + { url = "https://files.pythonhosted.org/packages/88/8b/e28f86412317b9514692fd6f9d8ac6faa12494c3f470c3c63f202e10c756/coverage-7.6.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b", size = 207406 }, + { url = "https://files.pythonhosted.org/packages/ac/46/da1bd9a3a893f74f5ce85f35e2755fcb00a80ed21e18d300c54f64938b1c/coverage-7.6.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c", size = 240424 }, + { url = "https://files.pythonhosted.org/packages/f6/12/af8e932496de1997bf4a36785d025ddac6427cbaf6954f26c2edaf21a58a/coverage-7.6.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1", size = 237456 }, + { url = "https://files.pythonhosted.org/packages/60/a2/23eb11eb60f825a84397cb94701d6f41d2e8e88ad7d0ba2b4339f38435fb/coverage-7.6.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354", size = 239527 }, + { url = "https://files.pythonhosted.org/packages/47/9e/63b318bc469308a32b0fbd6c80e2ea05dd7a2b7e840a46b3974843083a8c/coverage-7.6.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433", size = 239011 }, + { url = "https://files.pythonhosted.org/packages/99/47/1e84b067df3f021dfbc9cba09ec9acd4cb64938648a234e5bdf3006fd08b/coverage-7.6.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f", size = 237316 }, + { url = "https://files.pythonhosted.org/packages/12/9d/96baaafc948d4a0ef2248a611d41051eea0917ef881d744879dd20be7c4a/coverage-7.6.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb", size = 238980 }, + { url = "https://files.pythonhosted.org/packages/87/d9/97af1886ca3f612d0cea2999d33e90d2f5b8fdf9bedc2d3bc75883efec4c/coverage-7.6.7-cp312-cp312-win32.whl", hash = "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76", size = 209801 }, + { url = "https://files.pythonhosted.org/packages/f8/4d/1e31c2018b1b3738154639f94188b1f54098fbf0f80c7ec104928576d0bb/coverage-7.6.7-cp312-cp312-win_amd64.whl", hash = "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c", size = 210587 }, + { url = "https://files.pythonhosted.org/packages/21/87/c590d0c7eeb884995d9d06b429c5e88e9fcd65d3a6a686d9476cb50b72a9/coverage-7.6.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3", size = 207199 }, + { url = "https://files.pythonhosted.org/packages/40/ee/c88473c4f69c952f4425fabe045cb78d2027634ce50c9d7f7987d389b604/coverage-7.6.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab", size = 207454 }, + { url = "https://files.pythonhosted.org/packages/b8/07/afda6e10c50e3a8c21020c5c1d1b4f3d7eff1c190305cef2962adf8de018/coverage-7.6.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808", size = 239971 }, + { url = "https://files.pythonhosted.org/packages/85/43/bd1934b75e31f2a49665be6a6b7f8bfaff7266ba19721bdb90239f5e9ed7/coverage-7.6.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc", size = 237119 }, + { url = "https://files.pythonhosted.org/packages/2b/19/7a70458c1624724086195b40628e91bc5b9ca180cdfefcc778285c49c7b2/coverage-7.6.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8", size = 239109 }, + { url = "https://files.pythonhosted.org/packages/f3/2c/3dee671415ff13c05ca68243b2264fc95a5eea57697cffa7986b68b8f608/coverage-7.6.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a", size = 238769 }, + { url = "https://files.pythonhosted.org/packages/37/ad/e0d1228638711aeacacc98d1197af6226b6d062d12c81a6bcc17d3234533/coverage-7.6.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55", size = 236854 }, + { url = "https://files.pythonhosted.org/packages/90/95/6467e9d9765a63c7f142703a7f212f6af114bd73a6c1cffeb7ad7f003a86/coverage-7.6.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384", size = 238701 }, + { url = "https://files.pythonhosted.org/packages/b2/7a/fc11a163f0fd6ce8539d0f1b565873fe6903b900214ff71b5d80d16154c3/coverage-7.6.7-cp313-cp313-win32.whl", hash = "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30", size = 209865 }, + { url = "https://files.pythonhosted.org/packages/f2/91/58be3a56efff0c3481e48e2caa56d5d6f3c5c8d385bf4adbecdfd85484b0/coverage-7.6.7-cp313-cp313-win_amd64.whl", hash = "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42", size = 210597 }, + { url = "https://files.pythonhosted.org/packages/34/7e/fed983809c2eccb09c5ddccfdb08efb7f2dd1ae3454dabf1c92c5a2e9946/coverage-7.6.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413", size = 207944 }, + { url = "https://files.pythonhosted.org/packages/c7/e0/2c1a157986a3927c3920e8e3938a3fdf33ea22b6f371dc3b679f13f619e2/coverage-7.6.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd", size = 208215 }, + { url = "https://files.pythonhosted.org/packages/35/2f/77b086b228f6443ae5499467d1629c7428925b390cd171350c403bc00f14/coverage-7.6.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37", size = 250930 }, + { url = "https://files.pythonhosted.org/packages/60/d8/2ffea937d89ee328fc6e47c2515b890735bdf3f195d507d1c78b5fa96939/coverage-7.6.7-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b", size = 246647 }, + { url = "https://files.pythonhosted.org/packages/b2/81/efbb3b00a7f7eb5f54a3b3b9f19b26d770a0b7d3870d651f07d2451c5504/coverage-7.6.7-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d", size = 249006 }, + { url = "https://files.pythonhosted.org/packages/eb/91/ce36990cbefaf7909e96c888ed4d83f3471fc1be3273a5beda10896cde0f/coverage-7.6.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529", size = 248500 }, + { url = "https://files.pythonhosted.org/packages/75/3f/b8c87dfdd96276870fb4abc7e2957cba7d20d8a435fcd816d807869ec833/coverage-7.6.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b", size = 246388 }, + { url = "https://files.pythonhosted.org/packages/a0/51/62273e1d5c25bb8fbef5fbbadc75b4a3e08c11b80516d0a97c25e5cced5b/coverage-7.6.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3", size = 247669 }, + { url = "https://files.pythonhosted.org/packages/75/e5/d7772e56a7eace80e98ac39f2756d4b690fc0ce2384418174e02519a26a8/coverage-7.6.7-cp313-cp313t-win32.whl", hash = "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8", size = 210510 }, + { url = "https://files.pythonhosted.org/packages/2d/12/f2666e4e36b43221391ffcd971ab0c50e19439c521c2c87cd7e0b49ddba2/coverage-7.6.7-cp313-cp313t-win_amd64.whl", hash = "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56", size = 211660 }, + { url = "https://files.pythonhosted.org/packages/4c/3d/5ee1ccc37d39e4c06194492e15cd6327d0a85b6c4f14c112fd19b65dc6a7/coverage-7.6.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874", size = 206870 }, + { url = "https://files.pythonhosted.org/packages/c2/91/cfdf3c9f4c141d2172b5abd9631853144537d4849d00d08eff2b7e3a8318/coverage-7.6.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0", size = 207305 }, + { url = "https://files.pythonhosted.org/packages/0f/67/6b0460017083bd9330d2d74e3b5aff3e85f9918c96ae8eae8135a262cc34/coverage-7.6.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c", size = 235338 }, + { url = "https://files.pythonhosted.org/packages/92/59/0c3a8a3f5ef007862774cb8d25580ba8cc3a60e79d2e0798efb117eaea7b/coverage-7.6.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7", size = 233259 }, + { url = "https://files.pythonhosted.org/packages/cd/fc/68d19fb8688d976cb0da7713ca632ca5a5423c92aeae377161d9b888bb38/coverage-7.6.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3", size = 234387 }, + { url = "https://files.pythonhosted.org/packages/9d/8a/e76da4084c59420f4f9fac8a5d4b08f0281774f56375c59e76e27eafdb8d/coverage-7.6.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327", size = 233539 }, + { url = "https://files.pythonhosted.org/packages/61/b7/cc00329039500147d3b5724ca412e6b5b8124da7c2865b673a09f04e71fa/coverage-7.6.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c", size = 232021 }, + { url = "https://files.pythonhosted.org/packages/a1/af/1710b65f590d52c9c5f1a238142feb2ef1ff61915fa41531b372e920bee3/coverage-7.6.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289", size = 233013 }, + { url = "https://files.pythonhosted.org/packages/fc/99/32773e1f26cbfe11a0cadc4a4163a2249f04e83f0b8def93d85c572d0628/coverage-7.6.7-cp39-cp39-win32.whl", hash = "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c", size = 209597 }, + { url = "https://files.pythonhosted.org/packages/d7/ef/4b86263d312da7df483a84b69b4e0575fd777fb673fbef95a4df8a68a07c/coverage-7.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13", size = 210367 }, + { url = "https://files.pythonhosted.org/packages/e1/ec/dc663f7d34651aca74a531d10800595d9ec28a78b8306705721900b17a23/coverage-7.6.7-pp39.pp310-none-any.whl", hash = "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671", size = 199113 }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "cytoolz" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "toolz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e2/4c/ca9b05bdfa28ddbb4a5365c27021a1d4be61db7d8f6b4e5d4e76aa4ba3b7/cytoolz-1.0.0.tar.gz", hash = "sha256:eb453b30182152f9917a5189b7d99046b6ce90cdf8aeb0feff4b2683e600defd", size = 626708 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/77/2afed35b93fdc38c4565ae79aca6b6149d0ea2fc4eeeca9b0adf9da04b9e/cytoolz-1.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ecf5a887acb8f079ab1b81612b1c889bcbe6611aa7804fd2df46ed310aa5a345", size = 403505 }, + { url = "https://files.pythonhosted.org/packages/a8/dc/6b5af6932b656213883557dcc6b1f843ec302dc02fec4b75bf1356b938f9/cytoolz-1.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef0ef30c1e091d4d59d14d8108a16d50bd227be5d52a47da891da5019ac2f8e4", size = 383918 }, + { url = "https://files.pythonhosted.org/packages/2e/8c/d42dc240cda418b8241541c240c4696cf99475141c4d58fbe89b8c39bac1/cytoolz-1.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7df2dfd679f0517a96ced1cdd22f5c6c6aeeed28d928a82a02bf4c3fd6fd7ac4", size = 1934558 }, + { url = "https://files.pythonhosted.org/packages/ff/74/af7863cc407ebf535aec9adf0cb72bbac2f036ec2550726d4d8ab00eb41c/cytoolz-1.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c51452c938e610f57551aa96e34924169c9100c0448bac88c2fb395cbd3538c", size = 2015123 }, + { url = "https://files.pythonhosted.org/packages/01/98/83a0d9051e56e0b26a290439bd15b696c431c91d1dca384370cf9b23f04a/cytoolz-1.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6433f03910c5e5345d82d6299457c26bf33821224ebb837c6b09d9cdbc414a6c", size = 2000496 }, + { url = "https://files.pythonhosted.org/packages/d1/2d/ea68ba5d9c07f5d6cdb8ef85ec92f1a573deaad998807d035d2ef71aeb00/cytoolz-1.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:389ec328bb535f09e71dfe658bf0041f17194ca4cedaacd39bafe7893497a819", size = 1957529 }, + { url = "https://files.pythonhosted.org/packages/7d/f3/e5b6b7128412bcb8d58c5cbd5a785befdc2c633502653937be41a54b2037/cytoolz-1.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c64658e1209517ce4b54c1c9269a508b289d8d55fc742760e4b8579eacf09a33", size = 1863322 }, + { url = "https://files.pythonhosted.org/packages/ee/ff/534c227de78e9c45c6e764b46830640f73390b7fe5dd39556cd4de4fd3b8/cytoolz-1.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f6039a9bd5bb988762458b9ca82b39e60ca5e5baae2ba93913990dcc5d19fa88", size = 1849933 }, + { url = "https://files.pythonhosted.org/packages/ef/a9/7a51c084ceba8809f18aacb0bae86caf02aa5d5ebe5d5465819228a690d0/cytoolz-1.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:85c9c8c4465ed1b2c8d67003809aec9627b129cb531d2f6cf0bbfe39952e7e4d", size = 1852341 }, + { url = "https://files.pythonhosted.org/packages/ae/01/9b00fa8956c6b76ffd72fc896b2ba4e06165d7f90e03cf4ff253a4282d01/cytoolz-1.0.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:49375aad431d76650f94877afb92f09f58b6ff9055079ef4f2cd55313f5a1b39", size = 1989871 }, + { url = "https://files.pythonhosted.org/packages/30/5a/3857a60ce3083d083fffcac13938ae045d22ee0a55f88b83a22443132e5d/cytoolz-1.0.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:4c45106171c824a61e755355520b646cb35a1987b34bbf5789443823ee137f63", size = 1994484 }, + { url = "https://files.pythonhosted.org/packages/6c/3d/8585a635ebeba67f234f7779926519fda732399dd875b7cdff2cb2a3bff7/cytoolz-1.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3b319a7f0fed5db07d189db4046162ebc183c108df3562a65ba6ebe862d1f634", size = 1896072 }, + { url = "https://files.pythonhosted.org/packages/4c/3f/9f208381c12d2c8437ea09eef56f12c6f44af74ef5bc7546ca4fb099979e/cytoolz-1.0.0-cp310-cp310-win32.whl", hash = "sha256:9770e1b09748ad0d751853d994991e2592a9f8c464a87014365f80dac2e83faa", size = 322319 }, + { url = "https://files.pythonhosted.org/packages/d7/95/cbc120ba4f70f874481f6ec650d26c265db1645fb5285a81e589d5831073/cytoolz-1.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:20194dd02954c00c1f0755e636be75a20781f91a4ac9270c7f747e82d3c7f5a5", size = 363803 }, + { url = "https://files.pythonhosted.org/packages/bc/99/b489081777ad02c9bba294c757583416d0bdbd9403017145aba68145c16f/cytoolz-1.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dffc22fd2c91be64dbdbc462d0786f8e8ac9a275cfa1869a1084d1867d4f67e0", size = 406148 }, + { url = "https://files.pythonhosted.org/packages/b2/d3/a4d58bf89924dbca34e8dbb643b26935e08c16b4a2ee255d43a8b7489939/cytoolz-1.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a99e7e29274e293f4ffe20e07f76c2ac753a78f1b40c1828dfc54b2981b2f6c4", size = 384956 }, + { url = "https://files.pythonhosted.org/packages/81/d4/4d09e6571ef3b143f668c590a7a00c97ff24e6df6901f457ea7c782cd2ba/cytoolz-1.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c507a3e0a45c41d66b43f96797290d75d1e7a8549aa03a4a6b8854fdf3f7b8d8", size = 2091688 }, + { url = "https://files.pythonhosted.org/packages/8d/7b/68c89bed2e0490e9b946574c3bc79711179f35b1dc5eb31046c535f1bed2/cytoolz-1.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:643a593ec272ef7429099e1182a22f64ec2696c00d295d2a5be390db1b7ff176", size = 2188448 }, + { url = "https://files.pythonhosted.org/packages/56/a3/4e536fc7b72fd7495e19180463e8160a4fe1d50ab59a5854fc596621d5c3/cytoolz-1.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ce38e2e42cbae30446190c59b92a8a9029e1806fd79eaf88f48b0fe33003893", size = 2174196 }, + { url = "https://files.pythonhosted.org/packages/5a/7f/0451778af9e22755a95ef4400ee7fc6e41387521ab0f17699593cb07169a/cytoolz-1.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810a6a168b8c5ecb412fbae3dd6f7ed6c6253a63caf4174ee9794ebd29b2224f", size = 2099823 }, + { url = "https://files.pythonhosted.org/packages/58/b7/8ffdef1ac8f74b0cc650b9d4a74d93d911a7e20fcf7cc0abac0f4bce225f/cytoolz-1.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ce8a2a85c0741c1b19b16e6782c4a5abc54c3caecda66793447112ab2fa9884", size = 1996733 }, + { url = "https://files.pythonhosted.org/packages/1c/ab/9c694c883f3038d167b797cc55c64c2bdb64146428000cea15f235f30a0f/cytoolz-1.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ea4ac72e6b830861035c4c7999af8e55813f57c6d1913a3d93cc4a6babc27bf7", size = 2013725 }, + { url = "https://files.pythonhosted.org/packages/6c/df/859faaee91c795dc969c79cd38159031f373828d44b0b18999feb7d9a44d/cytoolz-1.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a09cdfb21dfb38aa04df43e7546a41f673377eb5485da88ceb784e327ec7603b", size = 1994851 }, + { url = "https://files.pythonhosted.org/packages/34/2a/26ac5a34e859c5ba32351f5a74492f4ed12e7a7e75b6afccf11c4100aa70/cytoolz-1.0.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:658dd85deb375ff7af990a674e5c9058cef1c9d1f5dc89bc87b77be499348144", size = 2155343 }, + { url = "https://files.pythonhosted.org/packages/3d/41/f687d2e40407b29bfcce36a7d456dad368283ea543aa39da53bcc119974e/cytoolz-1.0.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9715d1ff5576919d10b68f17241375f6a1eec8961c25b78a83e6ef1487053f39", size = 2163507 }, + { url = "https://files.pythonhosted.org/packages/39/7c/70d529f909d97ea214d59923c19e3d05a3768fe8e2066542b72550a31ca4/cytoolz-1.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f370a1f1f1afc5c1c8cc5edc1cfe0ba444263a0772af7ce094be8e734f41769d", size = 2054428 }, + { url = "https://files.pythonhosted.org/packages/5a/4a/7bb2eafe4077f6d9867547ca74ca4b75bc8a081e32a47e186e5c067f6cab/cytoolz-1.0.0-cp311-cp311-win32.whl", hash = "sha256:dbb2ec1177dca700f3db2127e572da20de280c214fc587b2a11c717fc421af56", size = 322300 }, + { url = "https://files.pythonhosted.org/packages/5a/ed/a1c955444343224ab1317a41f6575bc640055eb2495e8f9175f8f28bd776/cytoolz-1.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:0983eee73df86e54bb4a79fcc4996aa8b8368fdbf43897f02f9c3bf39c4dc4fb", size = 365539 }, + { url = "https://files.pythonhosted.org/packages/28/2e/a8b71f74ee75f33164bfbc6324ddd1e8d0f425255b1c930141516f51d539/cytoolz-1.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:10e3986066dc379e30e225b230754d9f5996aa8d84c2accc69c473c21d261e46", size = 414110 }, + { url = "https://files.pythonhosted.org/packages/c6/0a/999af6bb896375b0c687e292a3dcd4edb338a2764bbac40c0ce11eb21c64/cytoolz-1.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:16576f1bb143ee2cb9f719fcc4b845879fb121f9075c7c5e8a5ff4854bd02fc6", size = 390900 }, + { url = "https://files.pythonhosted.org/packages/30/04/02f0ee5339f8c6ef785f06caee85e17e8e0b406e7e553c8fd99a55ff8390/cytoolz-1.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3faa25a1840b984315e8b3ae517312375f4273ffc9a2f035f548b7f916884f37", size = 2090729 }, + { url = "https://files.pythonhosted.org/packages/04/de/296ded5f81ada90ae4db8c06cc34b142cf6c51fabb4c3c78583abba91c36/cytoolz-1.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:781fce70a277b20fd95dc66811d1a97bb07b611ceea9bda8b7dd3c6a4b05d59a", size = 2155926 }, + { url = "https://files.pythonhosted.org/packages/cc/ce/d5782bdd3d2fd16d87e83e70e14fcfa65ba67ba21cf7e1007505baef7d79/cytoolz-1.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7a562c25338eb24d419d1e80a7ae12133844ce6fdeb4ab54459daf250088a1b2", size = 2171893 }, + { url = "https://files.pythonhosted.org/packages/d0/02/22a8c74ff13f8a08e8cacd0a0aa34da3a6e3637cf477e376efc61f7567e5/cytoolz-1.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f29d8330aaf070304f7cd5cb7e73e198753624eb0aec278557cccd460c699b5b", size = 2125265 }, + { url = "https://files.pythonhosted.org/packages/50/d1/a3f2e2ced1fa7e2b5607d05ed4de9951491004a4804e96f78778d11bebd4/cytoolz-1.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:98a96c54aa55ed9c7cdb23c2f0df39a7b4ee518ac54888480b5bdb5ef69c7ef0", size = 1973962 }, + { url = "https://files.pythonhosted.org/packages/3e/10/174d9585e1011824e2e6e79380f8b1c6e49070c35a278d823d996d1c11e6/cytoolz-1.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:287d6d7f475882c2ddcbedf8da9a9b37d85b77690779a2d1cdceb5ae3998d52e", size = 2021691 }, + { url = "https://files.pythonhosted.org/packages/84/aa/bebdca3ae140698d3d4fe75ffd4c87a15ee999cee6b994e0831e5a24cdd7/cytoolz-1.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:05a871688df749b982839239fcd3f8ec3b3b4853775d575ff9cd335fa7c75035", size = 2010169 }, + { url = "https://files.pythonhosted.org/packages/2e/9f/8d5940c953534a4d2ae4419bb4fdc1eb5559345fed1f4838708073d7e6b4/cytoolz-1.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:28bb88e1e2f7d6d4b8e0890b06d292c568984d717de3e8381f2ca1dd12af6470", size = 2154314 }, + { url = "https://files.pythonhosted.org/packages/84/bf/a5414601c95afde30a0c038c5d6273c188f1da8ff25a057bd0c683679e5c/cytoolz-1.0.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:576a4f1fc73d8836b10458b583f915849da6e4f7914f4ecb623ad95c2508cad5", size = 2188368 }, + { url = "https://files.pythonhosted.org/packages/67/fe/990ea30d56b9b6602f3bf4af77a1bfd9233e6ffb761b11b8864619fed508/cytoolz-1.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:509ed3799c47e4ada14f63e41e8f540ac6e2dab97d5d7298934e6abb9d3830ec", size = 2077906 }, + { url = "https://files.pythonhosted.org/packages/ab/95/94b936501e1e23460732631e5d7c6efc4f6c09df21a594dfca9bf30b9411/cytoolz-1.0.0-cp312-cp312-win32.whl", hash = "sha256:9ce25f02b910630f6dc2540dd1e26c9326027ddde6c59f8cab07c56acc70714c", size = 322445 }, + { url = "https://files.pythonhosted.org/packages/be/04/a49b73591b132be5a28c0670229629a3c002cfac59582a1d38b16bdc6fed/cytoolz-1.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:7e53cfcce87e05b7f0ae2fb2b3e5820048cd0bb7b701e92bd8f75c9fbb7c9ae9", size = 364595 }, + { url = "https://files.pythonhosted.org/packages/9a/23/25205266c75212bdb417c44d9d353b751b74b22d205915c62566c820f1a9/cytoolz-1.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:05df5ff1cdd198fb57e7368623662578c950be0b14883cadfb9ee4098415e1e5", size = 405813 }, + { url = "https://files.pythonhosted.org/packages/71/a1/7de79ae7f87c24a5c6aeedba78a465b3a095945a568200326501c53ae06d/cytoolz-1.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04a84778f48ebddb26948971dc60948907c876ba33b13f9cbb014fe65b341fc2", size = 386288 }, + { url = "https://files.pythonhosted.org/packages/34/68/0ca87a17e3c7925eb100d797c8bbf3f9c1849decc6bee86ef06d8337073f/cytoolz-1.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f65283b618b4c4df759f57bcf8483865a73f7f268e6d76886c743407c8d26c1c", size = 1946289 }, + { url = "https://files.pythonhosted.org/packages/b7/74/f09a38a764a195ded241043e0f6bc4edc1843276cc002b9cd5af634cb6c0/cytoolz-1.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388cd07ee9a9e504c735a0a933e53c98586a1c301a64af81f7aa7ff40c747520", size = 2028077 }, + { url = "https://files.pythonhosted.org/packages/c6/6f/a084845345800d7bcfe730214b731bc46e1406863edb0073b24227cfd7a5/cytoolz-1.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06d09e9569cfdfc5c082806d4b4582db8023a3ce034097008622bcbac7236f38", size = 2012917 }, + { url = "https://files.pythonhosted.org/packages/59/6c/41910c59245dafaf34f0ac015943a49167b5fad0de8b456791bbaa37fdae/cytoolz-1.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9502bd9e37779cc9893cbab515a474c2ab6af61ed22ac2f7e16033db18fcaa85", size = 1969407 }, + { url = "https://files.pythonhosted.org/packages/ba/89/823f4c389200c0a82ed016ed2ac3f42747667945d86927aed308b31ba8c0/cytoolz-1.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:364c2fda148def38003b2c86e8adde1d2aab12411dd50872c244a815262e2fda", size = 1873873 }, + { url = "https://files.pythonhosted.org/packages/8c/6c/d5c35602079659fa043c92f54d2fa78ade7a6012d522510dc24a5081cd3b/cytoolz-1.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9b2e945617325242687189966335e785dc0fae316f4c1825baacf56e5a97e65f", size = 1861034 }, + { url = "https://files.pythonhosted.org/packages/fe/5c/e7fe8389a34e646fe89dad7c172652e30ced6e34d448f2e1d62f527d19e0/cytoolz-1.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0f16907fdc724c55b16776bdb7e629deae81d500fe48cfc3861231753b271355", size = 1864073 }, + { url = "https://files.pythonhosted.org/packages/5a/c5/33b2bd9e54b92ec60a9aacd89e000be20e718812109328d0f837bdfbbca4/cytoolz-1.0.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d3206c81ca3ba2d7b8fe78f2e116e3028e721148be753308e88dcbbc370bca52", size = 2002945 }, + { url = "https://files.pythonhosted.org/packages/de/66/6162abc03d4ea964112f8e3c1adc4c2b7f2c4696fccc327b8be6ee22303a/cytoolz-1.0.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:becce4b13e110b5ac6b23753dcd0c977f4fdccffa31898296e13fd1109e517e3", size = 2008118 }, + { url = "https://files.pythonhosted.org/packages/ef/35/08121353553de31d144ce3b9cfbf5b8a331a10fc9c8fbb2b74163b2a0c32/cytoolz-1.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:69a7e5e98fd446079b8b8ec5987aec9a31ec3570a6f494baefa6800b783eaf22", size = 1908761 }, + { url = "https://files.pythonhosted.org/packages/84/ac/80a772201ba560b0eb4a2c5d030fed7a9bcb8fcc68d0bfc7762a17f2b08b/cytoolz-1.0.0-cp39-cp39-win32.whl", hash = "sha256:b1707b6c3a91676ac83a28a231a14b337dbb4436b937e6b3e4fd44209852a48b", size = 324443 }, + { url = "https://files.pythonhosted.org/packages/45/72/1d512505cb4096d983f34bf5e20d473277fa03987a9af5748b76babe0a3f/cytoolz-1.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:11d48b8521ef5fe92e099f4fc00717b5d0789c3c90d5d84031b6d3b17dee1700", size = 366010 }, + { url = "https://files.pythonhosted.org/packages/16/7c/8b9fc006925b08579ae35293ad7d14fea4ee94edf1efaaa17e1bdde85b9a/cytoolz-1.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e672712d5dc3094afc6fb346dd4e9c18c1f3c69608ddb8cf3b9f8428f9c26a5c", size = 345694 }, + { url = "https://files.pythonhosted.org/packages/76/d1/159cc7c0c86d6fb8177be437dd6112d90c7f40ef0ceda2102472242b0ccf/cytoolz-1.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86fb208bfb7420e1d0d20065d661310e4a8a6884851d4044f47d37ed4cd7410e", size = 385691 }, + { url = "https://files.pythonhosted.org/packages/43/99/21361970f2d7cce241f116d84e8f5c21f1440414be96d0c8cad7832d35cb/cytoolz-1.0.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6dbe5fe3b835859fc559eb59bf2775b5a108f7f2cfab0966f3202859d787d8fd", size = 406251 }, + { url = "https://files.pythonhosted.org/packages/d8/98/bc3d6eadb495de0d48c4d738e5ee6f011d8adbf6a3fcc1f7c17d05bc49d3/cytoolz-1.0.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cace092dfda174eed09ed871793beb5b65633963bcda5b1632c73a5aceea1ce", size = 397203 }, + { url = "https://files.pythonhosted.org/packages/91/b1/df1ed78f08abe8781376bd197532e6e4b38bb3595dd82f6a2b8751407a52/cytoolz-1.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f7a9d816af3be9725c70efe0a6e4352a45d3877751b395014b8eb2f79d7d8d9d", size = 343504 }, + { url = "https://files.pythonhosted.org/packages/2c/f0/c7a6abe212a7840cf137d89c39ce0b8a866f0d492f9889c38f27d12de5c6/cytoolz-1.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:acfb8780c04d29423d14aaab74cd1b7b4beaba32f676e7ace02c9acfbf532aba", size = 344864 }, + { url = "https://files.pythonhosted.org/packages/c7/b5/445f60b7d7dfd338c7145743bd1acc1cc6683abda86f7a95dcd901b7ed9c/cytoolz-1.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99f39dcc46416dca3eb23664b73187b77fb52cd8ba2ddd8020a292d8f449db67", size = 384759 }, + { url = "https://files.pythonhosted.org/packages/16/09/74d7912c24b579af050629075601fe84cb2dbd29d3060387519b81b8e893/cytoolz-1.0.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0d56b3721977806dcf1a68b0ecd56feb382fdb0f632af1a9fc5ab9b662b32c6", size = 404911 }, + { url = "https://files.pythonhosted.org/packages/27/9b/327ff0bb2a5fb5997754119c48dc2ed6de3ace2818bd0311e64329ddc09b/cytoolz-1.0.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d346620abc8c83ae634136e700432ad6202faffcc24c5ab70b87392dcda8a1", size = 396277 }, + { url = "https://files.pythonhosted.org/packages/a6/9d/d63c319b717a0b79c636a91d34dc2e366a6843a3e1ca31c640aec9457660/cytoolz-1.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:df0c81197fc130de94c09fc6f024a6a19c98ba8fe55c17f1e45ebba2e9229079", size = 342954 }, +] + +[[package]] +name = "ecdsa" +version = "0.19.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/d0/ec8ac1de7accdcf18cfe468653ef00afd2f609faf67c423efbd02491051b/ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8", size = 197791 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/e7/ed3243b30d1bec41675b6394a1daae46349dc2b855cb83be846a5a918238/ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a", size = 149266 }, +] + +[[package]] +name = "eth-hash" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/b6/57c89b91cf2dbb02b3019337f97bf346167d06cd23d3bde43c9fe52cae7e/eth-hash-0.7.0.tar.gz", hash = "sha256:bacdc705bfd85dadd055ecd35fd1b4f846b671add101427e089a4ca2e8db310a", size = 12463 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/f0/a35e791bd73fa425838d8d0157754150ded141a94cf30d567dfeb9d57316/eth_hash-0.7.0-py3-none-any.whl", hash = "sha256:b8d5a230a2b251f4a291e3164a23a14057c4a6de4b0aa4a16fa4dc9161b57e2f", size = 8650 }, +] + +[[package]] +name = "eth-keys" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "eth-typing" }, + { name = "eth-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/4a/aabe0bff4e299858845fba5598c435f2bee0646366b9635750133904e2d8/eth_keys-0.6.0.tar.gz", hash = "sha256:ba33230f851d02c894e83989185b21d76152c49b37e35b61b1d8a6d9f1d20430", size = 28944 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/ee/583612eed5d49f10bd1749d7dda9e93691ab02724b7af84830046e31c64c/eth_keys-0.6.0-py3-none-any.whl", hash = "sha256:b396fdfe048a5bba3ef3990739aec64901eb99901c03921caa774be668b1db6e", size = 21210 }, +] + +[[package]] +name = "eth-typing" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/33/32/d5a1bdf872f92a7c3361396b684aeba7abaabb341bd22a80029abcd1f68e/eth_typing-5.0.1.tar.gz", hash = "sha256:83debf88c9df286db43bb7374974681ebcc9f048fac81be2548dbc549a3203c0", size = 22716 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/ef/a66ff9b83df51b83c1af468fc7b5e4a3855d9e3c01e2365ecfe1c5e84077/eth_typing-5.0.1-py3-none-any.whl", hash = "sha256:f30d1af16aac598f216748a952eeb64fbcb6e73efa691d2de31148138afe96de", size = 20085 }, +] + +[[package]] +name = "eth-utils" +version = "5.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cytoolz", marker = "implementation_name == 'cpython'" }, + { name = "eth-hash" }, + { name = "eth-typing" }, + { name = "toolz", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/b2/d5180e5dd01c5f5c9178274c7e27c67579c67554045370d3b8e60b562ea8/eth_utils-5.1.0.tar.gz", hash = "sha256:84c6314b9cf1fcd526107464bbf487e3f87097a2e753360d5ed319f7d42e3f20", size = 120325 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/19/e8d3e0e53dea8fb3054892e536cd1e02ebf492eeb4c42901763c2ae67f44/eth_utils-5.1.0-py3-none-any.whl", hash = "sha256:a99f1f01b51206620904c5af47fac65abc143aebd0a76bdec860381c5a3230f8", size = 100513 }, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, +] + +[[package]] +name = "frozenlist" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/ed/0f4cec13a93c02c47ec32d81d11c0c1efbadf4a471e3f3ce7cad366cbbd3/frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", size = 39930 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/79/29d44c4af36b2b240725dce566b20f63f9b36ef267aaaa64ee7466f4f2f8/frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a", size = 94451 }, + { url = "https://files.pythonhosted.org/packages/47/47/0c999aeace6ead8a44441b4f4173e2261b18219e4ad1fe9a479871ca02fc/frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb", size = 54301 }, + { url = "https://files.pythonhosted.org/packages/8d/60/107a38c1e54176d12e06e9d4b5d755b677d71d1219217cee063911b1384f/frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec", size = 52213 }, + { url = "https://files.pythonhosted.org/packages/17/62/594a6829ac5679c25755362a9dc93486a8a45241394564309641425d3ff6/frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5", size = 240946 }, + { url = "https://files.pythonhosted.org/packages/7e/75/6c8419d8f92c80dd0ee3f63bdde2702ce6398b0ac8410ff459f9b6f2f9cb/frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76", size = 264608 }, + { url = "https://files.pythonhosted.org/packages/88/3e/82a6f0b84bc6fb7e0be240e52863c6d4ab6098cd62e4f5b972cd31e002e8/frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17", size = 261361 }, + { url = "https://files.pythonhosted.org/packages/fd/85/14e5f9ccac1b64ff2f10c927b3ffdf88772aea875882406f9ba0cec8ad84/frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba", size = 231649 }, + { url = "https://files.pythonhosted.org/packages/ee/59/928322800306f6529d1852323014ee9008551e9bb027cc38d276cbc0b0e7/frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d", size = 241853 }, + { url = "https://files.pythonhosted.org/packages/7d/bd/e01fa4f146a6f6c18c5d34cab8abdc4013774a26c4ff851128cd1bd3008e/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2", size = 243652 }, + { url = "https://files.pythonhosted.org/packages/a5/bd/e4771fd18a8ec6757033f0fa903e447aecc3fbba54e3630397b61596acf0/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f", size = 241734 }, + { url = "https://files.pythonhosted.org/packages/21/13/c83821fa5544af4f60c5d3a65d054af3213c26b14d3f5f48e43e5fb48556/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c", size = 260959 }, + { url = "https://files.pythonhosted.org/packages/71/f3/1f91c9a9bf7ed0e8edcf52698d23f3c211d8d00291a53c9f115ceb977ab1/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab", size = 262706 }, + { url = "https://files.pythonhosted.org/packages/4c/22/4a256fdf5d9bcb3ae32622c796ee5ff9451b3a13a68cfe3f68e2c95588ce/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5", size = 250401 }, + { url = "https://files.pythonhosted.org/packages/af/89/c48ebe1f7991bd2be6d5f4ed202d94960c01b3017a03d6954dd5fa9ea1e8/frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb", size = 45498 }, + { url = "https://files.pythonhosted.org/packages/28/2f/cc27d5f43e023d21fe5c19538e08894db3d7e081cbf582ad5ed366c24446/frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4", size = 51622 }, + { url = "https://files.pythonhosted.org/packages/79/43/0bed28bf5eb1c9e4301003b74453b8e7aa85fb293b31dde352aac528dafc/frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30", size = 94987 }, + { url = "https://files.pythonhosted.org/packages/bb/bf/b74e38f09a246e8abbe1e90eb65787ed745ccab6eaa58b9c9308e052323d/frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5", size = 54584 }, + { url = "https://files.pythonhosted.org/packages/2c/31/ab01375682f14f7613a1ade30149f684c84f9b8823a4391ed950c8285656/frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778", size = 52499 }, + { url = "https://files.pythonhosted.org/packages/98/a8/d0ac0b9276e1404f58fec3ab6e90a4f76b778a49373ccaf6a563f100dfbc/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a", size = 276357 }, + { url = "https://files.pythonhosted.org/packages/ad/c9/c7761084fa822f07dac38ac29f841d4587570dd211e2262544aa0b791d21/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869", size = 287516 }, + { url = "https://files.pythonhosted.org/packages/a1/ff/cd7479e703c39df7bdab431798cef89dc75010d8aa0ca2514c5b9321db27/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d", size = 283131 }, + { url = "https://files.pythonhosted.org/packages/59/a0/370941beb47d237eca4fbf27e4e91389fd68699e6f4b0ebcc95da463835b/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45", size = 261320 }, + { url = "https://files.pythonhosted.org/packages/b8/5f/c10123e8d64867bc9b4f2f510a32042a306ff5fcd7e2e09e5ae5100ee333/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d", size = 274877 }, + { url = "https://files.pythonhosted.org/packages/fa/79/38c505601ae29d4348f21706c5d89755ceded02a745016ba2f58bd5f1ea6/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3", size = 269592 }, + { url = "https://files.pythonhosted.org/packages/19/e2/39f3a53191b8204ba9f0bb574b926b73dd2efba2a2b9d2d730517e8f7622/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a", size = 265934 }, + { url = "https://files.pythonhosted.org/packages/d5/c9/3075eb7f7f3a91f1a6b00284af4de0a65a9ae47084930916f5528144c9dd/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9", size = 283859 }, + { url = "https://files.pythonhosted.org/packages/05/f5/549f44d314c29408b962fa2b0e69a1a67c59379fb143b92a0a065ffd1f0f/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2", size = 287560 }, + { url = "https://files.pythonhosted.org/packages/9d/f8/cb09b3c24a3eac02c4c07a9558e11e9e244fb02bf62c85ac2106d1eb0c0b/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf", size = 277150 }, + { url = "https://files.pythonhosted.org/packages/37/48/38c2db3f54d1501e692d6fe058f45b6ad1b358d82cd19436efab80cfc965/frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942", size = 45244 }, + { url = "https://files.pythonhosted.org/packages/ca/8c/2ddffeb8b60a4bce3b196c32fcc30d8830d4615e7b492ec2071da801b8ad/frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d", size = 51634 }, + { url = "https://files.pythonhosted.org/packages/79/73/fa6d1a96ab7fd6e6d1c3500700963eab46813847f01ef0ccbaa726181dd5/frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21", size = 94026 }, + { url = "https://files.pythonhosted.org/packages/ab/04/ea8bf62c8868b8eada363f20ff1b647cf2e93377a7b284d36062d21d81d1/frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d", size = 54150 }, + { url = "https://files.pythonhosted.org/packages/d0/9a/8e479b482a6f2070b26bda572c5e6889bb3ba48977e81beea35b5ae13ece/frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e", size = 51927 }, + { url = "https://files.pythonhosted.org/packages/e3/12/2aad87deb08a4e7ccfb33600871bbe8f0e08cb6d8224371387f3303654d7/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a", size = 282647 }, + { url = "https://files.pythonhosted.org/packages/77/f2/07f06b05d8a427ea0060a9cef6e63405ea9e0d761846b95ef3fb3be57111/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a", size = 289052 }, + { url = "https://files.pythonhosted.org/packages/bd/9f/8bf45a2f1cd4aa401acd271b077989c9267ae8463e7c8b1eb0d3f561b65e/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee", size = 291719 }, + { url = "https://files.pythonhosted.org/packages/41/d1/1f20fd05a6c42d3868709b7604c9f15538a29e4f734c694c6bcfc3d3b935/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6", size = 267433 }, + { url = "https://files.pythonhosted.org/packages/af/f2/64b73a9bb86f5a89fb55450e97cd5c1f84a862d4ff90d9fd1a73ab0f64a5/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", size = 283591 }, + { url = "https://files.pythonhosted.org/packages/29/e2/ffbb1fae55a791fd6c2938dd9ea779509c977435ba3940b9f2e8dc9d5316/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9", size = 273249 }, + { url = "https://files.pythonhosted.org/packages/2e/6e/008136a30798bb63618a114b9321b5971172a5abddff44a100c7edc5ad4f/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039", size = 271075 }, + { url = "https://files.pythonhosted.org/packages/ae/f0/4e71e54a026b06724cec9b6c54f0b13a4e9e298cc8db0f82ec70e151f5ce/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784", size = 285398 }, + { url = "https://files.pythonhosted.org/packages/4d/36/70ec246851478b1c0b59f11ef8ade9c482ff447c1363c2bd5fad45098b12/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631", size = 294445 }, + { url = "https://files.pythonhosted.org/packages/37/e0/47f87544055b3349b633a03c4d94b405956cf2437f4ab46d0928b74b7526/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", size = 280569 }, + { url = "https://files.pythonhosted.org/packages/f9/7c/490133c160fb6b84ed374c266f42800e33b50c3bbab1652764e6e1fc498a/frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", size = 44721 }, + { url = "https://files.pythonhosted.org/packages/b1/56/4e45136ffc6bdbfa68c29ca56ef53783ef4c2fd395f7cbf99a2624aa9aaa/frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", size = 51329 }, + { url = "https://files.pythonhosted.org/packages/da/3b/915f0bca8a7ea04483622e84a9bd90033bab54bdf485479556c74fd5eaf5/frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", size = 91538 }, + { url = "https://files.pythonhosted.org/packages/c7/d1/a7c98aad7e44afe5306a2b068434a5830f1470675f0e715abb86eb15f15b/frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", size = 52849 }, + { url = "https://files.pythonhosted.org/packages/3a/c8/76f23bf9ab15d5f760eb48701909645f686f9c64fbb8982674c241fbef14/frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", size = 50583 }, + { url = "https://files.pythonhosted.org/packages/1f/22/462a3dd093d11df623179d7754a3b3269de3b42de2808cddef50ee0f4f48/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", size = 265636 }, + { url = "https://files.pythonhosted.org/packages/80/cf/e075e407fc2ae7328155a1cd7e22f932773c8073c1fc78016607d19cc3e5/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", size = 270214 }, + { url = "https://files.pythonhosted.org/packages/a1/58/0642d061d5de779f39c50cbb00df49682832923f3d2ebfb0fedf02d05f7f/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", size = 273905 }, + { url = "https://files.pythonhosted.org/packages/ab/66/3fe0f5f8f2add5b4ab7aa4e199f767fd3b55da26e3ca4ce2cc36698e50c4/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", size = 250542 }, + { url = "https://files.pythonhosted.org/packages/f6/b8/260791bde9198c87a465224e0e2bb62c4e716f5d198fc3a1dacc4895dbd1/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", size = 267026 }, + { url = "https://files.pythonhosted.org/packages/2e/a4/3d24f88c527f08f8d44ade24eaee83b2627793fa62fa07cbb7ff7a2f7d42/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", size = 257690 }, + { url = "https://files.pythonhosted.org/packages/de/9a/d311d660420b2beeff3459b6626f2ab4fb236d07afbdac034a4371fe696e/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", size = 253893 }, + { url = "https://files.pythonhosted.org/packages/c6/23/e491aadc25b56eabd0f18c53bb19f3cdc6de30b2129ee0bc39cd387cd560/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", size = 267006 }, + { url = "https://files.pythonhosted.org/packages/08/c4/ab918ce636a35fb974d13d666dcbe03969592aeca6c3ab3835acff01f79c/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", size = 276157 }, + { url = "https://files.pythonhosted.org/packages/c0/29/3b7a0bbbbe5a34833ba26f686aabfe982924adbdcafdc294a7a129c31688/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", size = 264642 }, + { url = "https://files.pythonhosted.org/packages/ab/42/0595b3dbffc2e82d7fe658c12d5a5bafcd7516c6bf2d1d1feb5387caa9c1/frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", size = 44914 }, + { url = "https://files.pythonhosted.org/packages/17/c4/b7db1206a3fea44bf3b838ca61deb6f74424a8a5db1dd53ecb21da669be6/frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", size = 51167 }, + { url = "https://files.pythonhosted.org/packages/da/4d/d94ff0fb0f5313902c132817c62d19cdc5bdcd0c195d392006ef4b779fc6/frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972", size = 95319 }, + { url = "https://files.pythonhosted.org/packages/8c/1b/d90e554ca2b483d31cb2296e393f72c25bdc38d64526579e95576bfda587/frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336", size = 54749 }, + { url = "https://files.pythonhosted.org/packages/f8/66/7fdecc9ef49f8db2aa4d9da916e4ecf357d867d87aea292efc11e1b2e932/frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f", size = 52718 }, + { url = "https://files.pythonhosted.org/packages/08/04/e2fddc92135276e07addbc1cf413acffa0c2d848b3e54cacf684e146df49/frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f", size = 241756 }, + { url = "https://files.pythonhosted.org/packages/c6/52/be5ff200815d8a341aee5b16b6b707355e0ca3652953852238eb92b120c2/frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6", size = 267718 }, + { url = "https://files.pythonhosted.org/packages/88/be/4bd93a58be57a3722fc544c36debdf9dcc6758f761092e894d78f18b8f20/frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411", size = 263494 }, + { url = "https://files.pythonhosted.org/packages/32/ba/58348b90193caa096ce9e9befea6ae67f38dabfd3aacb47e46137a6250a8/frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08", size = 232838 }, + { url = "https://files.pythonhosted.org/packages/f6/33/9f152105227630246135188901373c4f322cc026565ca6215b063f4c82f4/frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2", size = 242912 }, + { url = "https://files.pythonhosted.org/packages/a0/10/3db38fb3ccbafadd80a1b0d6800c987b0e3fe3ef2d117c6ced0246eea17a/frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d", size = 244763 }, + { url = "https://files.pythonhosted.org/packages/e2/cd/1df468fdce2f66a4608dffe44c40cdc35eeaa67ef7fd1d813f99a9a37842/frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b", size = 242841 }, + { url = "https://files.pythonhosted.org/packages/ee/5f/16097a5ca0bb6b6779c02cc9379c72fe98d56115d4c54d059fb233168fb6/frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b", size = 263407 }, + { url = "https://files.pythonhosted.org/packages/0f/f7/58cd220ee1c2248ee65a32f5b4b93689e3fe1764d85537eee9fc392543bc/frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0", size = 265083 }, + { url = "https://files.pythonhosted.org/packages/62/b8/49768980caabf81ac4a2d156008f7cbd0107e6b36d08a313bb31035d9201/frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c", size = 251564 }, + { url = "https://files.pythonhosted.org/packages/cb/83/619327da3b86ef957ee7a0cbf3c166a09ed1e87a3f7f1ff487d7d0284683/frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3", size = 45691 }, + { url = "https://files.pythonhosted.org/packages/8b/28/407bc34a745151ed2322c690b6e7d83d7101472e81ed76e1ebdac0b70a78/frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0", size = 51767 }, + { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034 }, +] + +[[package]] +name = "griffe" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d4/c9/8167810358ca129839156dc002526e7398b5fad4a9d7b6e88b875e802d0d/griffe-1.5.1.tar.gz", hash = "sha256:72964f93e08c553257706d6cd2c42d1c172213feb48b2be386f243380b405d4b", size = 384113 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/00/e693a155da0a2a72fd2df75b8fe338146cae59d590ad6f56800adde90cb5/griffe-1.5.1-py3-none-any.whl", hash = "sha256:ad6a7980f8c424c9102160aafa3bcdf799df0e75f7829d75af9ee5aef656f860", size = 127132 }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, +] + +[[package]] +name = "importlib-metadata" +version = "8.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", size = 55304 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514 }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 }, +] + +[[package]] +name = "markdown" +version = "3.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/28/3af612670f82f4c056911fbbbb42760255801b3068c48de792d354ff4472/markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2", size = 357086 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357 }, + { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393 }, + { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732 }, + { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866 }, + { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964 }, + { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977 }, + { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366 }, + { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091 }, + { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065 }, + { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514 }, + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, + { url = "https://files.pythonhosted.org/packages/a7/ea/9b1530c3fdeeca613faeb0fb5cbcf2389d816072fab72a71b45749ef6062/MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", size = 14344 }, + { url = "https://files.pythonhosted.org/packages/4b/c2/fbdbfe48848e7112ab05e627e718e854d20192b674952d9042ebd8c9e5de/MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", size = 12389 }, + { url = "https://files.pythonhosted.org/packages/f0/25/7a7c6e4dbd4f867d95d94ca15449e91e52856f6ed1905d58ef1de5e211d0/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", size = 21607 }, + { url = "https://files.pythonhosted.org/packages/53/8f/f339c98a178f3c1e545622206b40986a4c3307fe39f70ccd3d9df9a9e425/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", size = 20728 }, + { url = "https://files.pythonhosted.org/packages/1a/03/8496a1a78308456dbd50b23a385c69b41f2e9661c67ea1329849a598a8f9/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", size = 20826 }, + { url = "https://files.pythonhosted.org/packages/e6/cf/0a490a4bd363048c3022f2f475c8c05582179bb179defcee4766fb3dcc18/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", size = 21843 }, + { url = "https://files.pythonhosted.org/packages/19/a3/34187a78613920dfd3cdf68ef6ce5e99c4f3417f035694074beb8848cd77/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", size = 21219 }, + { url = "https://files.pythonhosted.org/packages/17/d8/5811082f85bb88410ad7e452263af048d685669bbbfb7b595e8689152498/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", size = 20946 }, + { url = "https://files.pythonhosted.org/packages/7c/31/bd635fb5989440d9365c5e3c47556cfea121c7803f5034ac843e8f37c2f2/MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", size = 15063 }, + { url = "https://files.pythonhosted.org/packages/b3/73/085399401383ce949f727afec55ec3abd76648d04b9f22e1c0e99cb4bec3/MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", size = 15506 }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354 }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "ghp-import" }, + { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451 }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/ae/0f1154c614d6a8b8a36fff084e5b82af3a15f7d2060cf0dcdb1c53297a71/mkdocs_autorefs-1.2.0.tar.gz", hash = "sha256:a86b93abff653521bda71cf3fc5596342b7a23982093915cb74273f67522190f", size = 40262 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/26/4d39d52ea2219604053a4d05b98e90d6a335511cc01806436ec4886b1028/mkdocs_autorefs-1.2.0-py3-none-any.whl", hash = "sha256:d588754ae89bd0ced0c70c06f58566a4ee43471eeeee5202427da7de9ef85a2f", size = 16522 }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521 }, +] + +[[package]] +name = "mkdocs-material" +version = "9.5.45" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/02/38f1f76252462b8e9652eb3778905206c1f3b9b4c25bf60aafc029675a2b/mkdocs_material-9.5.45.tar.gz", hash = "sha256:286489cf0beca4a129d91d59d6417419c63bceed1ce5cd0ec1fc7e1ebffb8189", size = 3906694 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/43/f5f866cd840e14f82068831e53446ea1f66a128cd38a229c5b9c9243ed9e/mkdocs_material-9.5.45-py3-none-any.whl", hash = "sha256:a9be237cfd0be14be75f40f1726d83aa3a81ce44808dc3594d47a7a592f44547", size = 8615700 }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728 }, +] + +[[package]] +name = "mkdocstrings" +version = "0.27.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "platformdirs" }, + { name = "pymdown-extensions" }, + { name = "typing-extensions", marker = "python_full_version < '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e2/5a/5de70538c2cefae7ac3a15b5601e306ef3717290cb2aab11d51cbbc2d1c0/mkdocstrings-0.27.0.tar.gz", hash = "sha256:16adca6d6b0a1f9e0c07ff0b02ced8e16f228a9d65a37c063ec4c14d7b76a657", size = 94830 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/10/4c27c3063c2b3681a4b7942f8dbdeb4fa34fecb2c19b594e7345ebf4f86f/mkdocstrings-0.27.0-py3-none-any.whl", hash = "sha256:6ceaa7ea830770959b55a16203ac63da24badd71325b96af950e59fd37366332", size = 30658 }, +] + +[package.optional-dependencies] +python = [ + { name = "mkdocstrings-python" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "1.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffe" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/23/ec/cb6debe2db77f1ef42b25b21d93b5021474de3037cd82385e586aee72545/mkdocstrings_python-1.12.2.tar.gz", hash = "sha256:7a1760941c0b52a2cd87b960a9e21112ffe52e7df9d0b9583d04d47ed2e186f3", size = 168207 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/c1/ac524e1026d9580cbc654b5d19f5843c8b364a66d30f956372cd09fd2f92/mkdocstrings_python-1.12.2-py3-none-any.whl", hash = "sha256:7f7d40d6db3cb1f5d19dbcd80e3efe4d0ba32b073272c0c0de9de2e604eda62a", size = 111759 }, +] + +[[package]] +name = "more-itertools" +version = "10.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/78/65922308c4248e0eb08ebcbe67c95d48615cc6f27854b6f2e57143e9178f/more-itertools-10.5.0.tar.gz", hash = "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6", size = 121020 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/7e/3a64597054a70f7c86eb0a7d4fc315b8c1ab932f64883a297bdffeb5f967/more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", size = 60952 }, +] + +[[package]] +name = "multidict" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/be/504b89a5e9ca731cd47487e91c469064f8ae5af93b7259758dcfc2b9c848/multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", size = 64002 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/68/259dee7fd14cf56a17c554125e534f6274c2860159692a414d0b402b9a6d/multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", size = 48628 }, + { url = "https://files.pythonhosted.org/packages/50/79/53ba256069fe5386a4a9e80d4e12857ced9de295baf3e20c68cdda746e04/multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", size = 29327 }, + { url = "https://files.pythonhosted.org/packages/ff/10/71f1379b05b196dae749b5ac062e87273e3f11634f447ebac12a571d90ae/multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", size = 29689 }, + { url = "https://files.pythonhosted.org/packages/71/45/70bac4f87438ded36ad4793793c0095de6572d433d98575a5752629ef549/multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", size = 126639 }, + { url = "https://files.pythonhosted.org/packages/80/cf/17f35b3b9509b4959303c05379c4bfb0d7dd05c3306039fc79cf035bbac0/multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", size = 134315 }, + { url = "https://files.pythonhosted.org/packages/ef/1f/652d70ab5effb33c031510a3503d4d6efc5ec93153562f1ee0acdc895a57/multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", size = 129471 }, + { url = "https://files.pythonhosted.org/packages/a6/64/2dd6c4c681688c0165dea3975a6a4eab4944ea30f35000f8b8af1df3148c/multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", size = 124585 }, + { url = "https://files.pythonhosted.org/packages/87/56/e6ee5459894c7e554b57ba88f7257dc3c3d2d379cb15baaa1e265b8c6165/multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", size = 116957 }, + { url = "https://files.pythonhosted.org/packages/36/9e/616ce5e8d375c24b84f14fc263c7ef1d8d5e8ef529dbc0f1df8ce71bb5b8/multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db", size = 128609 }, + { url = "https://files.pythonhosted.org/packages/8c/4f/4783e48a38495d000f2124020dc96bacc806a4340345211b1ab6175a6cb4/multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", size = 123016 }, + { url = "https://files.pythonhosted.org/packages/3e/b3/4950551ab8fc39862ba5e9907dc821f896aa829b4524b4deefd3e12945ab/multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", size = 133542 }, + { url = "https://files.pythonhosted.org/packages/96/4d/f0ce6ac9914168a2a71df117935bb1f1781916acdecbb43285e225b484b8/multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", size = 130163 }, + { url = "https://files.pythonhosted.org/packages/be/72/17c9f67e7542a49dd252c5ae50248607dfb780bcc03035907dafefb067e3/multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", size = 126832 }, + { url = "https://files.pythonhosted.org/packages/71/9f/72d719e248cbd755c8736c6d14780533a1606ffb3fbb0fbd77da9f0372da/multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", size = 26402 }, + { url = "https://files.pythonhosted.org/packages/04/5a/d88cd5d00a184e1ddffc82aa2e6e915164a6d2641ed3606e766b5d2f275a/multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", size = 28800 }, + { url = "https://files.pythonhosted.org/packages/93/13/df3505a46d0cd08428e4c8169a196131d1b0c4b515c3649829258843dde6/multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", size = 48570 }, + { url = "https://files.pythonhosted.org/packages/f0/e1/a215908bfae1343cdb72f805366592bdd60487b4232d039c437fe8f5013d/multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", size = 29316 }, + { url = "https://files.pythonhosted.org/packages/70/0f/6dc70ddf5d442702ed74f298d69977f904960b82368532c88e854b79f72b/multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", size = 29640 }, + { url = "https://files.pythonhosted.org/packages/d8/6d/9c87b73a13d1cdea30b321ef4b3824449866bd7f7127eceed066ccb9b9ff/multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", size = 131067 }, + { url = "https://files.pythonhosted.org/packages/cc/1e/1b34154fef373371fd6c65125b3d42ff5f56c7ccc6bfff91b9b3c60ae9e0/multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", size = 138507 }, + { url = "https://files.pythonhosted.org/packages/fb/e0/0bc6b2bac6e461822b5f575eae85da6aae76d0e2a79b6665d6206b8e2e48/multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", size = 133905 }, + { url = "https://files.pythonhosted.org/packages/ba/af/73d13b918071ff9b2205fcf773d316e0f8fefb4ec65354bbcf0b10908cc6/multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", size = 129004 }, + { url = "https://files.pythonhosted.org/packages/74/21/23960627b00ed39643302d81bcda44c9444ebcdc04ee5bedd0757513f259/multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", size = 121308 }, + { url = "https://files.pythonhosted.org/packages/8b/5c/cf282263ffce4a596ed0bb2aa1a1dddfe1996d6a62d08842a8d4b33dca13/multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", size = 132608 }, + { url = "https://files.pythonhosted.org/packages/d7/3e/97e778c041c72063f42b290888daff008d3ab1427f5b09b714f5a8eff294/multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", size = 127029 }, + { url = "https://files.pythonhosted.org/packages/47/ac/3efb7bfe2f3aefcf8d103e9a7162572f01936155ab2f7ebcc7c255a23212/multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", size = 137594 }, + { url = "https://files.pythonhosted.org/packages/42/9b/6c6e9e8dc4f915fc90a9b7798c44a30773dea2995fdcb619870e705afe2b/multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", size = 134556 }, + { url = "https://files.pythonhosted.org/packages/1d/10/8e881743b26aaf718379a14ac58572a240e8293a1c9d68e1418fb11c0f90/multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", size = 130993 }, + { url = "https://files.pythonhosted.org/packages/45/84/3eb91b4b557442802d058a7579e864b329968c8d0ea57d907e7023c677f2/multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", size = 26405 }, + { url = "https://files.pythonhosted.org/packages/9f/0b/ad879847ecbf6d27e90a6eabb7eff6b62c129eefe617ea45eae7c1f0aead/multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", size = 28795 }, + { url = "https://files.pythonhosted.org/packages/fd/16/92057c74ba3b96d5e211b553895cd6dc7cc4d1e43d9ab8fafc727681ef71/multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", size = 48713 }, + { url = "https://files.pythonhosted.org/packages/94/3d/37d1b8893ae79716179540b89fc6a0ee56b4a65fcc0d63535c6f5d96f217/multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", size = 29516 }, + { url = "https://files.pythonhosted.org/packages/a2/12/adb6b3200c363062f805275b4c1e656be2b3681aada66c80129932ff0bae/multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", size = 29557 }, + { url = "https://files.pythonhosted.org/packages/47/e9/604bb05e6e5bce1e6a5cf80a474e0f072e80d8ac105f1b994a53e0b28c42/multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", size = 130170 }, + { url = "https://files.pythonhosted.org/packages/7e/13/9efa50801785eccbf7086b3c83b71a4fb501a4d43549c2f2f80b8787d69f/multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", size = 134836 }, + { url = "https://files.pythonhosted.org/packages/bf/0f/93808b765192780d117814a6dfcc2e75de6dcc610009ad408b8814dca3ba/multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", size = 133475 }, + { url = "https://files.pythonhosted.org/packages/d3/c8/529101d7176fe7dfe1d99604e48d69c5dfdcadb4f06561f465c8ef12b4df/multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", size = 131049 }, + { url = "https://files.pythonhosted.org/packages/ca/0c/fc85b439014d5a58063e19c3a158a889deec399d47b5269a0f3b6a2e28bc/multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", size = 120370 }, + { url = "https://files.pythonhosted.org/packages/db/46/d4416eb20176492d2258fbd47b4abe729ff3b6e9c829ea4236f93c865089/multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", size = 125178 }, + { url = "https://files.pythonhosted.org/packages/5b/46/73697ad7ec521df7de5531a32780bbfd908ded0643cbe457f981a701457c/multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", size = 119567 }, + { url = "https://files.pythonhosted.org/packages/cd/ed/51f060e2cb0e7635329fa6ff930aa5cffa17f4c7f5c6c3ddc3500708e2f2/multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", size = 129822 }, + { url = "https://files.pythonhosted.org/packages/df/9e/ee7d1954b1331da3eddea0c4e08d9142da5f14b1321c7301f5014f49d492/multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", size = 128656 }, + { url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 }, + { url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 }, + { url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 }, + { url = "https://files.pythonhosted.org/packages/22/67/1c7c0f39fe069aa4e5d794f323be24bf4d33d62d2a348acdb7991f8f30db/multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", size = 48771 }, + { url = "https://files.pythonhosted.org/packages/3c/25/c186ee7b212bdf0df2519eacfb1981a017bda34392c67542c274651daf23/multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", size = 29533 }, + { url = "https://files.pythonhosted.org/packages/67/5e/04575fd837e0958e324ca035b339cea174554f6f641d3fb2b4f2e7ff44a2/multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", size = 29595 }, + { url = "https://files.pythonhosted.org/packages/d3/b2/e56388f86663810c07cfe4a3c3d87227f3811eeb2d08450b9e5d19d78876/multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", size = 130094 }, + { url = "https://files.pythonhosted.org/packages/6c/ee/30ae9b4186a644d284543d55d491fbd4239b015d36b23fea43b4c94f7052/multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", size = 134876 }, + { url = "https://files.pythonhosted.org/packages/84/c7/70461c13ba8ce3c779503c70ec9d0345ae84de04521c1f45a04d5f48943d/multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", size = 133500 }, + { url = "https://files.pythonhosted.org/packages/4a/9f/002af221253f10f99959561123fae676148dd730e2daa2cd053846a58507/multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", size = 131099 }, + { url = "https://files.pythonhosted.org/packages/82/42/d1c7a7301d52af79d88548a97e297f9d99c961ad76bbe6f67442bb77f097/multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", size = 120403 }, + { url = "https://files.pythonhosted.org/packages/68/f3/471985c2c7ac707547553e8f37cff5158030d36bdec4414cb825fbaa5327/multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", size = 125348 }, + { url = "https://files.pythonhosted.org/packages/67/2c/e6df05c77e0e433c214ec1d21ddd203d9a4770a1f2866a8ca40a545869a0/multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", size = 119673 }, + { url = "https://files.pythonhosted.org/packages/c5/cd/bc8608fff06239c9fb333f9db7743a1b2eafe98c2666c9a196e867a3a0a4/multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", size = 129927 }, + { url = "https://files.pythonhosted.org/packages/44/8e/281b69b7bc84fc963a44dc6e0bbcc7150e517b91df368a27834299a526ac/multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", size = 128711 }, + { url = "https://files.pythonhosted.org/packages/12/a4/63e7cd38ed29dd9f1881d5119f272c898ca92536cdb53ffe0843197f6c85/multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", size = 125519 }, + { url = "https://files.pythonhosted.org/packages/38/e0/4f5855037a72cd8a7a2f60a3952d9aa45feedb37ae7831642102604e8a37/multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", size = 26426 }, + { url = "https://files.pythonhosted.org/packages/7e/a5/17ee3a4db1e310b7405f5d25834460073a8ccd86198ce044dfaf69eac073/multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", size = 28531 }, + { url = "https://files.pythonhosted.org/packages/e7/c9/9e153a6572b38ac5ff4434113af38acf8d5e9957897cdb1f513b3d6614ed/multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", size = 48550 }, + { url = "https://files.pythonhosted.org/packages/76/f5/79565ddb629eba6c7f704f09a09df085c8dc04643b12506f10f718cee37a/multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", size = 29298 }, + { url = "https://files.pythonhosted.org/packages/60/1b/9851878b704bc98e641a3e0bce49382ae9e05743dac6d97748feb5b7baba/multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", size = 29641 }, + { url = "https://files.pythonhosted.org/packages/89/87/d451d45aab9e422cb0fb2f7720c31a4c1d3012c740483c37f642eba568fb/multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", size = 126202 }, + { url = "https://files.pythonhosted.org/packages/fa/b4/27cbe9f3e2e469359887653f2e45470272eef7295139916cc21107c6b48c/multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", size = 133925 }, + { url = "https://files.pythonhosted.org/packages/4d/a3/afc841899face8adfd004235ce759a37619f6ec99eafd959650c5ce4df57/multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", size = 129039 }, + { url = "https://files.pythonhosted.org/packages/5e/41/0d0fb18c1ad574f807196f5f3d99164edf9de3e169a58c6dc2d6ed5742b9/multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", size = 124072 }, + { url = "https://files.pythonhosted.org/packages/00/22/defd7a2e71a44e6e5b9a5428f972e5b572e7fe28e404dfa6519bbf057c93/multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", size = 116532 }, + { url = "https://files.pythonhosted.org/packages/91/25/f7545102def0b1d456ab6449388eed2dfd822debba1d65af60194904a23a/multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", size = 128173 }, + { url = "https://files.pythonhosted.org/packages/45/79/3dbe8d35fc99f5ea610813a72ab55f426cb9cf482f860fa8496e5409be11/multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", size = 122654 }, + { url = "https://files.pythonhosted.org/packages/97/cb/209e735eeab96e1b160825b5d0b36c56d3862abff828fc43999bb957dcad/multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", size = 133197 }, + { url = "https://files.pythonhosted.org/packages/e4/3a/a13808a7ada62808afccea67837a79d00ad6581440015ef00f726d064c2d/multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", size = 129754 }, + { url = "https://files.pythonhosted.org/packages/77/dd/8540e139eafb240079242da8f8ffdf9d3f4b4ad1aac5a786cd4050923783/multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", size = 126402 }, + { url = "https://files.pythonhosted.org/packages/86/99/e82e1a275d8b1ea16d3a251474262258dbbe41c05cce0c01bceda1fc8ea5/multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", size = 26421 }, + { url = "https://files.pythonhosted.org/packages/86/1c/9fa630272355af7e4446a2c7550c259f11ee422ab2d30ff90a0a71cf3d9e/multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", size = 28791 }, + { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 }, +] + +[[package]] +name = "mypy" +version = "1.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/8c/206de95a27722b5b5a8c85ba3100467bd86299d92a4f71c6b9aa448bfa2f/mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a", size = 11020731 }, + { url = "https://files.pythonhosted.org/packages/ab/bb/b31695a29eea76b1569fd28b4ab141a1adc9842edde080d1e8e1776862c7/mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80", size = 10184276 }, + { url = "https://files.pythonhosted.org/packages/a5/2d/4a23849729bb27934a0e079c9c1aad912167d875c7b070382a408d459651/mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7", size = 12587706 }, + { url = "https://files.pythonhosted.org/packages/5c/c3/d318e38ada50255e22e23353a469c791379825240e71b0ad03e76ca07ae6/mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f", size = 13105586 }, + { url = "https://files.pythonhosted.org/packages/4a/25/3918bc64952370c3dbdbd8c82c363804678127815febd2925b7273d9482c/mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372", size = 9632318 }, + { url = "https://files.pythonhosted.org/packages/d0/19/de0822609e5b93d02579075248c7aa6ceaddcea92f00bf4ea8e4c22e3598/mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d", size = 10939027 }, + { url = "https://files.pythonhosted.org/packages/c8/71/6950fcc6ca84179137e4cbf7cf41e6b68b4a339a1f5d3e954f8c34e02d66/mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d", size = 10108699 }, + { url = "https://files.pythonhosted.org/packages/26/50/29d3e7dd166e74dc13d46050b23f7d6d7533acf48f5217663a3719db024e/mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b", size = 12506263 }, + { url = "https://files.pythonhosted.org/packages/3f/1d/676e76f07f7d5ddcd4227af3938a9c9640f293b7d8a44dd4ff41d4db25c1/mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73", size = 12984688 }, + { url = "https://files.pythonhosted.org/packages/9c/03/5a85a30ae5407b1d28fab51bd3e2103e52ad0918d1e68f02a7778669a307/mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca", size = 9626811 }, + { url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900 }, + { url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818 }, + { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 }, + { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 }, + { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 }, + { url = "https://files.pythonhosted.org/packages/11/bb/ab4cfdc562cad80418f077d8be9b4491ee4fb257440da951b85cbb0a639e/mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", size = 11069721 }, + { url = "https://files.pythonhosted.org/packages/59/3b/a393b1607cb749ea2c621def5ba8c58308ff05e30d9dbdc7c15028bca111/mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", size = 10063996 }, + { url = "https://files.pythonhosted.org/packages/d1/1f/6b76be289a5a521bb1caedc1f08e76ff17ab59061007f201a8a18cc514d1/mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8", size = 12584043 }, + { url = "https://files.pythonhosted.org/packages/a6/83/5a85c9a5976c6f96e3a5a7591aa28b4a6ca3a07e9e5ba0cec090c8b596d6/mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7", size = 13036996 }, + { url = "https://files.pythonhosted.org/packages/b4/59/c39a6f752f1f893fccbcf1bdd2aca67c79c842402b5283563d006a67cf76/mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc", size = 9737709 }, + { url = "https://files.pythonhosted.org/packages/5f/d4/b33ddd40dad230efb317898a2d1c267c04edba73bc5086bf77edeb410fb2/mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc", size = 11013906 }, + { url = "https://files.pythonhosted.org/packages/f4/e6/f414bca465b44d01cd5f4a82761e15044bedd1bf8025c5af3cc64518fac5/mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732", size = 10180657 }, + { url = "https://files.pythonhosted.org/packages/38/e9/fc3865e417722f98d58409770be01afb961e2c1f99930659ff4ae7ca8b7e/mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc", size = 12586394 }, + { url = "https://files.pythonhosted.org/packages/2e/35/f4d8b6d2cb0b3dad63e96caf159419dda023f45a358c6c9ac582ccaee354/mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d", size = 13103591 }, + { url = "https://files.pythonhosted.org/packages/22/1d/80594aef135f921dd52e142fa0acd19df197690bd0cde42cea7b88cf5aa2/mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24", size = 9634690 }, + { url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043 }, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, +] + +[[package]] +name = "orjson" +version = "3.10.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/04/bb9f72987e7f62fb591d6c880c0caaa16238e4e530cbc3bdc84a7372d75f/orjson-3.10.12.tar.gz", hash = "sha256:0a78bbda3aea0f9f079057ee1ee8a1ecf790d4f1af88dd67493c6b8ee52506ff", size = 5438647 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/d2/78652b67f86d093dca984ce3fa5bf819ee1462627da83e7d0b784a9a7c45/orjson-3.10.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ece01a7ec71d9940cc654c482907a6b65df27251255097629d0dea781f255c6d", size = 248688 }, + { url = "https://files.pythonhosted.org/packages/70/cb/f8b6a52f3bc724edf8a62d8d1d8ee17cf19d6ae1cac89f077f0e7c30f396/orjson-3.10.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c34ec9aebc04f11f4b978dd6caf697a2df2dd9b47d35aa4cc606cabcb9df69d7", size = 136952 }, + { url = "https://files.pythonhosted.org/packages/a6/43/c55700df9814545bc8c35d87395ec4b9ee473a3c1f5ed72f8d3ad0298ee9/orjson-3.10.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd6ec8658da3480939c79b9e9e27e0db31dffcd4ba69c334e98c9976ac29140e", size = 149089 }, + { url = "https://files.pythonhosted.org/packages/07/da/e7e7d73bd971710b736fbd8330b8830c5fa4fc0ac003b31af61f03b26dfc/orjson-3.10.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17e6baf4cf01534c9de8a16c0c611f3d94925d1701bf5f4aff17003677d8ced", size = 140479 }, + { url = "https://files.pythonhosted.org/packages/08/49/c9dfddba56ff24eecfacf2f01a76cae4d249ac2995b1359bf63a74b1b318/orjson-3.10.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6402ebb74a14ef96f94a868569f5dccf70d791de49feb73180eb3c6fda2ade56", size = 156564 }, + { url = "https://files.pythonhosted.org/packages/96/df/174d2eff227dc23b4540a0c2efa6ec8fe406c442c4b7f0f556242f026d1f/orjson-3.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0000758ae7c7853e0a4a6063f534c61656ebff644391e1f81698c1b2d2fc8cd2", size = 131282 }, + { url = "https://files.pythonhosted.org/packages/6a/96/8628c53a52e2a0a1ee861d809092df72aabbd312c71de9ad6d49e2c039ab/orjson-3.10.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:888442dcee99fd1e5bd37a4abb94930915ca6af4db50e23e746cdf4d1e63db13", size = 139764 }, + { url = "https://files.pythonhosted.org/packages/38/17/08becb49e59e7bb7b29dc1dad19bc0c48635e627ee27e60eb5b64efcf7b1/orjson-3.10.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c1f7a3ce79246aa0e92f5458d86c54f257fb5dfdc14a192651ba7ec2c00f8a05", size = 131913 }, + { url = "https://files.pythonhosted.org/packages/2a/05/f32acc2500e3fafee9445eb8b2a6ff19c4641035e6059c6c8d7bdb3abc9e/orjson-3.10.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:802a3935f45605c66fb4a586488a38af63cb37aaad1c1d94c982c40dcc452e85", size = 415782 }, + { url = "https://files.pythonhosted.org/packages/06/03/6cc740d998d8bb60e75d4b7e228d18964475239ac842cc1865d49d092545/orjson-3.10.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1da1ef0113a2be19bb6c557fb0ec2d79c92ebd2fed4cfb1b26bab93f021fb885", size = 142383 }, + { url = "https://files.pythonhosted.org/packages/f8/30/39cac82547fe021615376245c558b216d3ae8c99bd6b2274f312e49f1c94/orjson-3.10.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a3273e99f367f137d5b3fecb5e9f45bcdbfac2a8b2f32fbc72129bbd48789c2", size = 130661 }, + { url = "https://files.pythonhosted.org/packages/95/29/c6837f4fc1eaa742eaf5abcd767ab6805493f44fe1f72b37c1743706c1d8/orjson-3.10.12-cp310-none-win32.whl", hash = "sha256:475661bf249fd7907d9b0a2a2421b4e684355a77ceef85b8352439a9163418c3", size = 143625 }, + { url = "https://files.pythonhosted.org/packages/f6/62/c6b955f2144421108fa441b5471e1d5f8654a7df9840b261106e04d5d15c/orjson-3.10.12-cp310-none-win_amd64.whl", hash = "sha256:87251dc1fb2b9e5ab91ce65d8f4caf21910d99ba8fb24b49fd0c118b2362d509", size = 135075 }, + { url = "https://files.pythonhosted.org/packages/d3/48/7c3cd094488f5a3bc58488555244609a8c4d105bc02f2b77e509debf0450/orjson-3.10.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a734c62efa42e7df94926d70fe7d37621c783dea9f707a98cdea796964d4cf74", size = 248687 }, + { url = "https://files.pythonhosted.org/packages/ff/90/e55f0e25c7fdd1f82551fe787f85df6f378170caca863c04c810cd8f2730/orjson-3.10.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:750f8b27259d3409eda8350c2919a58b0cfcd2054ddc1bd317a643afc646ef23", size = 136953 }, + { url = "https://files.pythonhosted.org/packages/2a/b3/109c020cf7fee747d400de53b43b183ca9d3ebda3906ad0b858eb5479718/orjson-3.10.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb52c22bfffe2857e7aa13b4622afd0dd9d16ea7cc65fd2bf318d3223b1b6252", size = 149090 }, + { url = "https://files.pythonhosted.org/packages/96/d4/35c0275dc1350707d182a1b5da16d1184b9439848060af541285407f18f9/orjson-3.10.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:440d9a337ac8c199ff8251e100c62e9488924c92852362cd27af0e67308c16ef", size = 140480 }, + { url = "https://files.pythonhosted.org/packages/3b/79/f863ff460c291ad2d882cc3b580cc444bd4ec60c9df55f6901e6c9a3f519/orjson-3.10.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9e15c06491c69997dfa067369baab3bf094ecb74be9912bdc4339972323f252", size = 156564 }, + { url = "https://files.pythonhosted.org/packages/98/7e/8d5835449ddd873424ee7b1c4ba73a0369c1055750990d824081652874d6/orjson-3.10.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:362d204ad4b0b8724cf370d0cd917bb2dc913c394030da748a3bb632445ce7c4", size = 131279 }, + { url = "https://files.pythonhosted.org/packages/46/f5/d34595b6d7f4f984c6fef289269a7f98abcdc2445ebdf90e9273487dda6b/orjson-3.10.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b57cbb4031153db37b41622eac67329c7810e5f480fda4cfd30542186f006ae", size = 139764 }, + { url = "https://files.pythonhosted.org/packages/b3/5b/ee6e9ddeab54a7b7806768151c2090a2d36025bc346a944f51cf172ef7f7/orjson-3.10.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:165c89b53ef03ce0d7c59ca5c82fa65fe13ddf52eeb22e859e58c237d4e33b9b", size = 131915 }, + { url = "https://files.pythonhosted.org/packages/c4/45/febee5951aef6db5cd8cdb260548101d7ece0ca9d4ddadadf1766306b7a4/orjson-3.10.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5dee91b8dfd54557c1a1596eb90bcd47dbcd26b0baaed919e6861f076583e9da", size = 415783 }, + { url = "https://files.pythonhosted.org/packages/27/a5/5a8569e49f3a6c093bee954a3de95062a231196f59e59df13a48e2420081/orjson-3.10.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a4e1cfb72de6f905bdff061172adfb3caf7a4578ebf481d8f0530879476c07", size = 142387 }, + { url = "https://files.pythonhosted.org/packages/6e/05/02550fb38c5bf758f3994f55401233a2ef304e175f473f2ac6dbf464cc8b/orjson-3.10.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:038d42c7bc0606443459b8fe2d1f121db474c49067d8d14c6a075bbea8bf14dd", size = 130664 }, + { url = "https://files.pythonhosted.org/packages/8c/f4/ba31019d0646ce51f7ac75af6dabf98fd89dbf8ad87a9086da34710738e7/orjson-3.10.12-cp311-none-win32.whl", hash = "sha256:03b553c02ab39bed249bedd4abe37b2118324d1674e639b33fab3d1dafdf4d79", size = 143623 }, + { url = "https://files.pythonhosted.org/packages/83/fe/babf08842b989acf4c46103fefbd7301f026423fab47e6f3ba07b54d7837/orjson-3.10.12-cp311-none-win_amd64.whl", hash = "sha256:8b8713b9e46a45b2af6b96f559bfb13b1e02006f4242c156cbadef27800a55a8", size = 135074 }, + { url = "https://files.pythonhosted.org/packages/a1/2f/989adcafad49afb535da56b95d8f87d82e748548b2a86003ac129314079c/orjson-3.10.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53206d72eb656ca5ac7d3a7141e83c5bbd3ac30d5eccfe019409177a57634b0d", size = 248678 }, + { url = "https://files.pythonhosted.org/packages/69/b9/8c075e21a50c387649db262b618ebb7e4d40f4197b949c146fc225dd23da/orjson-3.10.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8010afc2150d417ebda810e8df08dd3f544e0dd2acab5370cfa6bcc0662f8f", size = 136763 }, + { url = "https://files.pythonhosted.org/packages/87/d3/78edf10b4ab14c19f6d918cf46a145818f4aca2b5a1773c894c5490d3a4c/orjson-3.10.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed459b46012ae950dd2e17150e838ab08215421487371fa79d0eced8d1461d70", size = 149137 }, + { url = "https://files.pythonhosted.org/packages/16/81/5db8852bdf990a0ddc997fa8f16b80895b8cc77c0fe3701569ed2b4b9e78/orjson-3.10.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dcb9673f108a93c1b52bfc51b0af422c2d08d4fc710ce9c839faad25020bb69", size = 140567 }, + { url = "https://files.pythonhosted.org/packages/fa/a6/9ce1e3e3db918512efadad489630c25841eb148513d21dab96f6b4157fa1/orjson-3.10.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22a51ae77680c5c4652ebc63a83d5255ac7d65582891d9424b566fb3b5375ee9", size = 156620 }, + { url = "https://files.pythonhosted.org/packages/47/d4/05133d6bea24e292d2f7628b1e19986554f7d97b6412b3e51d812e38db2d/orjson-3.10.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910fdf2ac0637b9a77d1aad65f803bac414f0b06f720073438a7bd8906298192", size = 131555 }, + { url = "https://files.pythonhosted.org/packages/b9/7a/b3fbffda8743135c7811e95dc2ab7cdbc5f04999b83c2957d046f1b3fac9/orjson-3.10.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24ce85f7100160936bc2116c09d1a8492639418633119a2224114f67f63a4559", size = 139743 }, + { url = "https://files.pythonhosted.org/packages/b5/13/95bbcc9a6584aa083da5ce5004ce3d59ea362a542a0b0938d884fd8790b6/orjson-3.10.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a76ba5fc8dd9c913640292df27bff80a685bed3a3c990d59aa6ce24c352f8fc", size = 131733 }, + { url = "https://files.pythonhosted.org/packages/e8/29/dddbb2ea6e7af426fcc3da65a370618a88141de75c6603313d70768d1df1/orjson-3.10.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ff70ef093895fd53f4055ca75f93f047e088d1430888ca1229393a7c0521100f", size = 415788 }, + { url = "https://files.pythonhosted.org/packages/53/df/4aea59324ac539975919b4705ee086aced38e351a6eb3eea0f5071dd5661/orjson-3.10.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f4244b7018b5753ecd10a6d324ec1f347da130c953a9c88432c7fbc8875d13be", size = 142347 }, + { url = "https://files.pythonhosted.org/packages/55/55/a52d83d7c49f8ff44e0daab10554490447d6c658771569e1c662aa7057fe/orjson-3.10.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:16135ccca03445f37921fa4b585cff9a58aa8d81ebcb27622e69bfadd220b32c", size = 130829 }, + { url = "https://files.pythonhosted.org/packages/a1/8b/b1beb1624dd4adf7d72e2d9b73c4b529e7851c0c754f17858ea13e368b33/orjson-3.10.12-cp312-none-win32.whl", hash = "sha256:2d879c81172d583e34153d524fcba5d4adafbab8349a7b9f16ae511c2cee8708", size = 143659 }, + { url = "https://files.pythonhosted.org/packages/13/91/634c9cd0bfc6a857fc8fab9bf1a1bd9f7f3345e0d6ca5c3d4569ceb6dcfa/orjson-3.10.12-cp312-none-win_amd64.whl", hash = "sha256:fc23f691fa0f5c140576b8c365bc942d577d861a9ee1142e4db468e4e17094fb", size = 135221 }, + { url = "https://files.pythonhosted.org/packages/1b/bb/3f560735f46fa6f875a9d7c4c2171a58cfb19f56a633d5ad5037a924f35f/orjson-3.10.12-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:47962841b2a8aa9a258b377f5188db31ba49af47d4003a32f55d6f8b19006543", size = 248662 }, + { url = "https://files.pythonhosted.org/packages/a3/df/54817902350636cc9270db20486442ab0e4db33b38555300a1159b439d16/orjson-3.10.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6334730e2532e77b6054e87ca84f3072bee308a45a452ea0bffbbbc40a67e296", size = 126055 }, + { url = "https://files.pythonhosted.org/packages/2e/77/55835914894e00332601a74540840f7665e81f20b3e2b9a97614af8565ed/orjson-3.10.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:accfe93f42713c899fdac2747e8d0d5c659592df2792888c6c5f829472e4f85e", size = 131507 }, + { url = "https://files.pythonhosted.org/packages/33/9e/b91288361898e3158062a876b5013c519a5d13e692ac7686e3486c4133ab/orjson-3.10.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7974c490c014c48810d1dede6c754c3cc46598da758c25ca3b4001ac45b703f", size = 131686 }, + { url = "https://files.pythonhosted.org/packages/b2/15/08ce117d60a4d2d3fd24e6b21db463139a658e9f52d22c9c30af279b4187/orjson-3.10.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3f250ce7727b0b2682f834a3facff88e310f52f07a5dcfd852d99637d386e79e", size = 415710 }, + { url = "https://files.pythonhosted.org/packages/71/af/c09da5ed58f9c002cf83adff7a4cdf3e6cee742aa9723395f8dcdb397233/orjson-3.10.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f31422ff9486ae484f10ffc51b5ab2a60359e92d0716fcce1b3593d7bb8a9af6", size = 142305 }, + { url = "https://files.pythonhosted.org/packages/17/d1/8612038d44f33fae231e9ba480d273bac2b0383ce9e77cb06bede1224ae3/orjson-3.10.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5f29c5d282bb2d577c2a6bbde88d8fdcc4919c593f806aac50133f01b733846e", size = 130815 }, + { url = "https://files.pythonhosted.org/packages/67/2c/d5f87834be3591555cfaf9aecdf28f480a6f0b4afeaac53bad534bf9518f/orjson-3.10.12-cp313-none-win32.whl", hash = "sha256:f45653775f38f63dc0e6cd4f14323984c3149c05d6007b58cb154dd080ddc0dc", size = 143664 }, + { url = "https://files.pythonhosted.org/packages/6a/05/7d768fa3ca23c9b3e1e09117abeded1501119f1d8de0ab722938c91ab25d/orjson-3.10.12-cp313-none-win_amd64.whl", hash = "sha256:229994d0c376d5bdc91d92b3c9e6be2f1fbabd4cc1b59daae1443a46ee5e9825", size = 134944 }, + { url = "https://files.pythonhosted.org/packages/01/50/5a52cfe65fc70e7b843cbe143b850313095d4e45f99aeb278b4b3691f3cf/orjson-3.10.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f29de3ef71a42a5822765def1febfb36e0859d33abf5c2ad240acad5c6a1b78d", size = 249130 }, + { url = "https://files.pythonhosted.org/packages/af/42/adb00fc60890e57ee6022257d70d9a20dfd28bfd955401e2d02a60192226/orjson-3.10.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de365a42acc65d74953f05e4772c974dad6c51cfc13c3240899f534d611be967", size = 136784 }, + { url = "https://files.pythonhosted.org/packages/f5/f6/5ef130a2e28a0c633c82da67224212fa84b17f93d9d768c255f389d66641/orjson-3.10.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a5a0158648a67ff0004cb0df5df7dcc55bfc9ca154d9c01597a23ad54c8d0c", size = 148936 }, + { url = "https://files.pythonhosted.org/packages/54/80/f40805bb094d3470bcfca8d30ae9f4606bb90c809190fee18c17a4653956/orjson-3.10.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c47ce6b8d90fe9646a25b6fb52284a14ff215c9595914af63a5933a49972ce36", size = 140291 }, + { url = "https://files.pythonhosted.org/packages/b4/0a/c91265a075af28fcb118a9a690dccc0f31c52dd7f486f5cc73aa6f9a69b4/orjson-3.10.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0eee4c2c5bfb5c1b47a5db80d2ac7aaa7e938956ae88089f098aff2c0f35d5d8", size = 156335 }, + { url = "https://files.pythonhosted.org/packages/6f/1f/c8fc64b25e2e4a5fa0fb514a0325719e99461c088a3b659954a57b8c1f3c/orjson-3.10.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d3081bbe8b86587eb5c98a73b97f13d8f9fea685cf91a579beddacc0d10566", size = 131118 }, + { url = "https://files.pythonhosted.org/packages/b3/f7/f5dba457bbc6aaf8ebd0131a17eb672835d2ea31f763d1462c191902bc10/orjson-3.10.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73c23a6e90383884068bc2dba83d5222c9fcc3b99a0ed2411d38150734236755", size = 139573 }, + { url = "https://files.pythonhosted.org/packages/85/03/87091a1c831076e8d6ed0be19d30bd837d3c27e29f43b6b2dc23efee3d29/orjson-3.10.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5472be7dc3269b4b52acba1433dac239215366f89dc1d8d0e64029abac4e714e", size = 131760 }, + { url = "https://files.pythonhosted.org/packages/53/70/956ca7999fe43b5e2ca51248f732850acaaf00f8fa5b8f7924bc504157bb/orjson-3.10.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7319cda750fca96ae5973efb31b17d97a5c5225ae0bc79bf5bf84df9e1ec2ab6", size = 415605 }, + { url = "https://files.pythonhosted.org/packages/ca/7f/4f49c1a9da03e383198c0fa418cc4262d01d70931742dfc504c2a495ed7b/orjson-3.10.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:74d5ca5a255bf20b8def6a2b96b1e18ad37b4a122d59b154c458ee9494377f80", size = 142208 }, + { url = "https://files.pythonhosted.org/packages/81/d9/0216c950e295b1c493510ef546b80328dc06e2ae4a82bc693386e4cdebeb/orjson-3.10.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ff31d22ecc5fb85ef62c7d4afe8301d10c558d00dd24274d4bbe464380d3cd69", size = 130495 }, + { url = "https://files.pythonhosted.org/packages/1a/d0/70d97b583d628a307d4bc1f96f7ab6cf137e32849c06ea03d4337ad19e14/orjson-3.10.12-cp39-none-win32.whl", hash = "sha256:c22c3ea6fba91d84fcb4cda30e64aff548fcf0c44c876e681f47d61d24b12e6b", size = 143467 }, + { url = "https://files.pythonhosted.org/packages/ec/a3/725e4cac70d2a88f5fc4f9eed451e12d594063823feb931c30ac1394d26f/orjson-3.10.12-cp39-none-win_amd64.whl", hash = "sha256:be604f60d45ace6b0b33dd990a66b4526f1a7a186ac411c942674625456ca548", size = 134927 }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746 }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + +[[package]] +name = "propcache" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/4d/5e5a60b78dbc1d464f8a7bbaeb30957257afdc8512cbb9dfd5659304f5cd/propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", size = 40951 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/08/1963dfb932b8d74d5b09098507b37e9b96c835ba89ab8aad35aa330f4ff3/propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58", size = 80712 }, + { url = "https://files.pythonhosted.org/packages/e6/59/49072aba9bf8a8ed958e576182d46f038e595b17ff7408bc7e8807e721e1/propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b", size = 46301 }, + { url = "https://files.pythonhosted.org/packages/33/a2/6b1978c2e0d80a678e2c483f45e5443c15fe5d32c483902e92a073314ef1/propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110", size = 45581 }, + { url = "https://files.pythonhosted.org/packages/43/95/55acc9adff8f997c7572f23d41993042290dfb29e404cdadb07039a4386f/propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2", size = 208659 }, + { url = "https://files.pythonhosted.org/packages/bd/2c/ef7371ff715e6cd19ea03fdd5637ecefbaa0752fee5b0f2fe8ea8407ee01/propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a", size = 222613 }, + { url = "https://files.pythonhosted.org/packages/5e/1c/fef251f79fd4971a413fa4b1ae369ee07727b4cc2c71e2d90dfcde664fbb/propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577", size = 221067 }, + { url = "https://files.pythonhosted.org/packages/8d/e7/22e76ae6fc5a1708bdce92bdb49de5ebe89a173db87e4ef597d6bbe9145a/propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850", size = 208920 }, + { url = "https://files.pythonhosted.org/packages/04/3e/f10aa562781bcd8a1e0b37683a23bef32bdbe501d9cc7e76969becaac30d/propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61", size = 200050 }, + { url = "https://files.pythonhosted.org/packages/d0/98/8ac69f638358c5f2a0043809c917802f96f86026e86726b65006830f3dc6/propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37", size = 202346 }, + { url = "https://files.pythonhosted.org/packages/ee/78/4acfc5544a5075d8e660af4d4e468d60c418bba93203d1363848444511ad/propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48", size = 199750 }, + { url = "https://files.pythonhosted.org/packages/a2/8f/90ada38448ca2e9cf25adc2fe05d08358bda1b9446f54a606ea38f41798b/propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630", size = 201279 }, + { url = "https://files.pythonhosted.org/packages/08/31/0e299f650f73903da851f50f576ef09bfffc8e1519e6a2f1e5ed2d19c591/propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394", size = 211035 }, + { url = "https://files.pythonhosted.org/packages/85/3e/e356cc6b09064bff1c06d0b2413593e7c925726f0139bc7acef8a21e87a8/propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b", size = 215565 }, + { url = "https://files.pythonhosted.org/packages/8b/54/4ef7236cd657e53098bd05aa59cbc3cbf7018fba37b40eaed112c3921e51/propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336", size = 207604 }, + { url = "https://files.pythonhosted.org/packages/1f/27/d01d7799c068443ee64002f0655d82fb067496897bf74b632e28ee6a32cf/propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad", size = 40526 }, + { url = "https://files.pythonhosted.org/packages/bb/44/6c2add5eeafb7f31ff0d25fbc005d930bea040a1364cf0f5768750ddf4d1/propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99", size = 44958 }, + { url = "https://files.pythonhosted.org/packages/e0/1c/71eec730e12aec6511e702ad0cd73c2872eccb7cad39de8ba3ba9de693ef/propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", size = 80811 }, + { url = "https://files.pythonhosted.org/packages/89/c3/7e94009f9a4934c48a371632197406a8860b9f08e3f7f7d922ab69e57a41/propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", size = 46365 }, + { url = "https://files.pythonhosted.org/packages/c0/1d/c700d16d1d6903aeab28372fe9999762f074b80b96a0ccc953175b858743/propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", size = 45602 }, + { url = "https://files.pythonhosted.org/packages/2e/5e/4a3e96380805bf742712e39a4534689f4cddf5fa2d3a93f22e9fd8001b23/propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", size = 236161 }, + { url = "https://files.pythonhosted.org/packages/a5/85/90132481183d1436dff6e29f4fa81b891afb6cb89a7306f32ac500a25932/propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", size = 244938 }, + { url = "https://files.pythonhosted.org/packages/4a/89/c893533cb45c79c970834274e2d0f6d64383ec740be631b6a0a1d2b4ddc0/propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", size = 243576 }, + { url = "https://files.pythonhosted.org/packages/8c/56/98c2054c8526331a05f205bf45cbb2cda4e58e56df70e76d6a509e5d6ec6/propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", size = 236011 }, + { url = "https://files.pythonhosted.org/packages/2d/0c/8b8b9f8a6e1abd869c0fa79b907228e7abb966919047d294ef5df0d136cf/propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504", size = 224834 }, + { url = "https://files.pythonhosted.org/packages/18/bb/397d05a7298b7711b90e13108db697732325cafdcd8484c894885c1bf109/propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", size = 224946 }, + { url = "https://files.pythonhosted.org/packages/25/19/4fc08dac19297ac58135c03770b42377be211622fd0147f015f78d47cd31/propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", size = 217280 }, + { url = "https://files.pythonhosted.org/packages/7e/76/c79276a43df2096ce2aba07ce47576832b1174c0c480fe6b04bd70120e59/propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", size = 220088 }, + { url = "https://files.pythonhosted.org/packages/c3/9a/8a8cf428a91b1336b883f09c8b884e1734c87f724d74b917129a24fe2093/propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", size = 233008 }, + { url = "https://files.pythonhosted.org/packages/25/7b/768a8969abd447d5f0f3333df85c6a5d94982a1bc9a89c53c154bf7a8b11/propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", size = 237719 }, + { url = "https://files.pythonhosted.org/packages/ed/0d/e5d68ccc7976ef8b57d80613ac07bbaf0614d43f4750cf953f0168ef114f/propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", size = 227729 }, + { url = "https://files.pythonhosted.org/packages/05/64/17eb2796e2d1c3d0c431dc5f40078d7282f4645af0bb4da9097fbb628c6c/propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", size = 40473 }, + { url = "https://files.pythonhosted.org/packages/83/c5/e89fc428ccdc897ade08cd7605f174c69390147526627a7650fb883e0cd0/propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", size = 44921 }, + { url = "https://files.pythonhosted.org/packages/7c/46/a41ca1097769fc548fc9216ec4c1471b772cc39720eb47ed7e38ef0006a9/propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", size = 80800 }, + { url = "https://files.pythonhosted.org/packages/75/4f/93df46aab9cc473498ff56be39b5f6ee1e33529223d7a4d8c0a6101a9ba2/propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", size = 46443 }, + { url = "https://files.pythonhosted.org/packages/0b/17/308acc6aee65d0f9a8375e36c4807ac6605d1f38074b1581bd4042b9fb37/propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", size = 45676 }, + { url = "https://files.pythonhosted.org/packages/65/44/626599d2854d6c1d4530b9a05e7ff2ee22b790358334b475ed7c89f7d625/propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", size = 246191 }, + { url = "https://files.pythonhosted.org/packages/f2/df/5d996d7cb18df076debae7d76ac3da085c0575a9f2be6b1f707fe227b54c/propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", size = 251791 }, + { url = "https://files.pythonhosted.org/packages/2e/6d/9f91e5dde8b1f662f6dd4dff36098ed22a1ef4e08e1316f05f4758f1576c/propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", size = 253434 }, + { url = "https://files.pythonhosted.org/packages/3c/e9/1b54b7e26f50b3e0497cd13d3483d781d284452c2c50dd2a615a92a087a3/propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", size = 248150 }, + { url = "https://files.pythonhosted.org/packages/a7/ef/a35bf191c8038fe3ce9a414b907371c81d102384eda5dbafe6f4dce0cf9b/propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", size = 233568 }, + { url = "https://files.pythonhosted.org/packages/97/d9/d00bb9277a9165a5e6d60f2142cd1a38a750045c9c12e47ae087f686d781/propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", size = 229874 }, + { url = "https://files.pythonhosted.org/packages/8e/78/c123cf22469bdc4b18efb78893e69c70a8b16de88e6160b69ca6bdd88b5d/propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", size = 225857 }, + { url = "https://files.pythonhosted.org/packages/31/1b/fd6b2f1f36d028820d35475be78859d8c89c8f091ad30e377ac49fd66359/propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", size = 227604 }, + { url = "https://files.pythonhosted.org/packages/99/36/b07be976edf77a07233ba712e53262937625af02154353171716894a86a6/propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", size = 238430 }, + { url = "https://files.pythonhosted.org/packages/0d/64/5822f496c9010e3966e934a011ac08cac8734561842bc7c1f65586e0683c/propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", size = 244814 }, + { url = "https://files.pythonhosted.org/packages/fd/bd/8657918a35d50b18a9e4d78a5df7b6c82a637a311ab20851eef4326305c1/propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", size = 235922 }, + { url = "https://files.pythonhosted.org/packages/a8/6f/ec0095e1647b4727db945213a9f395b1103c442ef65e54c62e92a72a3f75/propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", size = 40177 }, + { url = "https://files.pythonhosted.org/packages/20/a2/bd0896fdc4f4c1db46d9bc361c8c79a9bf08ccc08ba054a98e38e7ba1557/propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", size = 44446 }, + { url = "https://files.pythonhosted.org/packages/a8/a7/5f37b69197d4f558bfef5b4bceaff7c43cc9b51adf5bd75e9081d7ea80e4/propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", size = 78120 }, + { url = "https://files.pythonhosted.org/packages/c8/cd/48ab2b30a6b353ecb95a244915f85756d74f815862eb2ecc7a518d565b48/propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", size = 45127 }, + { url = "https://files.pythonhosted.org/packages/a5/ba/0a1ef94a3412aab057bd996ed5f0ac7458be5bf469e85c70fa9ceb43290b/propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", size = 44419 }, + { url = "https://files.pythonhosted.org/packages/b4/6c/ca70bee4f22fa99eacd04f4d2f1699be9d13538ccf22b3169a61c60a27fa/propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", size = 229611 }, + { url = "https://files.pythonhosted.org/packages/19/70/47b872a263e8511ca33718d96a10c17d3c853aefadeb86dc26e8421184b9/propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", size = 234005 }, + { url = "https://files.pythonhosted.org/packages/4f/be/3b0ab8c84a22e4a3224719099c1229ddfdd8a6a1558cf75cb55ee1e35c25/propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", size = 237270 }, + { url = "https://files.pythonhosted.org/packages/04/d8/f071bb000d4b8f851d312c3c75701e586b3f643fe14a2e3409b1b9ab3936/propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", size = 231877 }, + { url = "https://files.pythonhosted.org/packages/93/e7/57a035a1359e542bbb0a7df95aad6b9871ebee6dce2840cb157a415bd1f3/propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", size = 217848 }, + { url = "https://files.pythonhosted.org/packages/f0/93/d1dea40f112ec183398fb6c42fde340edd7bab202411c4aa1a8289f461b6/propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", size = 216987 }, + { url = "https://files.pythonhosted.org/packages/62/4c/877340871251145d3522c2b5d25c16a1690ad655fbab7bb9ece6b117e39f/propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", size = 212451 }, + { url = "https://files.pythonhosted.org/packages/7c/bb/a91b72efeeb42906ef58ccf0cdb87947b54d7475fee3c93425d732f16a61/propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", size = 212879 }, + { url = "https://files.pythonhosted.org/packages/9b/7f/ee7fea8faac57b3ec5d91ff47470c6c5d40d7f15d0b1fccac806348fa59e/propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", size = 222288 }, + { url = "https://files.pythonhosted.org/packages/ff/d7/acd67901c43d2e6b20a7a973d9d5fd543c6e277af29b1eb0e1f7bd7ca7d2/propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", size = 228257 }, + { url = "https://files.pythonhosted.org/packages/8d/6f/6272ecc7a8daad1d0754cfc6c8846076a8cb13f810005c79b15ce0ef0cf2/propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", size = 221075 }, + { url = "https://files.pythonhosted.org/packages/7c/bd/c7a6a719a6b3dd8b3aeadb3675b5783983529e4a3185946aa444d3e078f6/propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", size = 39654 }, + { url = "https://files.pythonhosted.org/packages/88/e7/0eef39eff84fa3e001b44de0bd41c7c0e3432e7648ffd3d64955910f002d/propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", size = 43705 }, + { url = "https://files.pythonhosted.org/packages/38/05/797e6738c9f44ab5039e3ff329540c934eabbe8ad7e63c305c75844bc86f/propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6", size = 81903 }, + { url = "https://files.pythonhosted.org/packages/9f/84/8d5edb9a73e1a56b24dd8f2adb6aac223109ff0e8002313d52e5518258ba/propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638", size = 46960 }, + { url = "https://files.pythonhosted.org/packages/e7/77/388697bedda984af0d12d68e536b98129b167282da3401965c8450de510e/propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957", size = 46133 }, + { url = "https://files.pythonhosted.org/packages/e2/dc/60d444610bc5b1d7a758534f58362b1bcee736a785473f8a39c91f05aad1/propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1", size = 211105 }, + { url = "https://files.pythonhosted.org/packages/bc/c6/40eb0dd1de6f8e84f454615ab61f68eb4a58f9d63d6f6eaf04300ac0cc17/propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562", size = 226613 }, + { url = "https://files.pythonhosted.org/packages/de/b6/e078b5e9de58e20db12135eb6a206b4b43cb26c6b62ee0fe36ac40763a64/propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d", size = 225587 }, + { url = "https://files.pythonhosted.org/packages/ce/4e/97059dd24494d1c93d1efb98bb24825e1930265b41858dd59c15cb37a975/propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12", size = 211826 }, + { url = "https://files.pythonhosted.org/packages/fc/23/4dbf726602a989d2280fe130a9b9dd71faa8d3bb8cd23d3261ff3c23f692/propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8", size = 203140 }, + { url = "https://files.pythonhosted.org/packages/5b/ce/f3bff82c885dbd9ae9e43f134d5b02516c3daa52d46f7a50e4f52ef9121f/propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8", size = 208841 }, + { url = "https://files.pythonhosted.org/packages/29/d7/19a4d3b4c7e95d08f216da97035d0b103d0c90411c6f739d47088d2da1f0/propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb", size = 203315 }, + { url = "https://files.pythonhosted.org/packages/db/87/5748212a18beb8d4ab46315c55ade8960d1e2cdc190764985b2d229dd3f4/propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea", size = 204724 }, + { url = "https://files.pythonhosted.org/packages/84/2a/c3d2f989fc571a5bad0fabcd970669ccb08c8f9b07b037ecddbdab16a040/propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6", size = 215514 }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4c44c133b08bc5f776afcb8f0833889c2636b8a83e07ea1d9096c1e401b0/propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d", size = 220063 }, + { url = "https://files.pythonhosted.org/packages/2e/25/280d0a3bdaee68db74c0acd9a472e59e64b516735b59cffd3a326ff9058a/propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798", size = 211620 }, + { url = "https://files.pythonhosted.org/packages/28/8c/266898981b7883c1563c35954f9ce9ced06019fdcc487a9520150c48dc91/propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9", size = 41049 }, + { url = "https://files.pythonhosted.org/packages/af/53/a3e5b937f58e757a940716b88105ec4c211c42790c1ea17052b46dc16f16/propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df", size = 45587 }, + { url = "https://files.pythonhosted.org/packages/3d/b6/e6d98278f2d49b22b4d033c9f792eda783b9ab2094b041f013fc69bcde87/propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", size = 11603 }, +] + +[[package]] +name = "py-bip39-bindings" +version = "0.1.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/a1/65aeab0f95b64d4f95034b3a6e32a44d156e300c1b00c3c6087235cb4658/py_bip39_bindings-0.1.12.tar.gz", hash = "sha256:56f446e665a4511e9e7dab807a908ca692247a257e141f76633110e3d30e53af", size = 15882 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/c1/e1161b3251975009fabf0e4d67895554ed4612d8416b9d5b060532754d6f/py_bip39_bindings-0.1.12-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:830a1cd07b46f84d07b9807ea1e378e947d95f9f69a1b4acc5012cf2e9336e47", size = 393630 }, + { url = "https://files.pythonhosted.org/packages/98/ae/ed9c88c076944f43f5632f9b748413a6bc25232042732b7a1d186b80f82d/py_bip39_bindings-0.1.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad84b1ca46329f23c808889d97bd79cc8a2c48e0b9fbf0ecefd16ba8c4e54761", size = 383959 }, + { url = "https://files.pythonhosted.org/packages/d1/47/57b56e586f9c4c6215c13857eb91d7518b7ec2c31b11b6cb0fa0cebf8638/py_bip39_bindings-0.1.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3772e233a03a322cd7d6587c393f24a6f98059fbeb723b05c536489671a9ae8a", size = 449117 }, + { url = "https://files.pythonhosted.org/packages/05/88/ed9df4cd6329dd19e87d27f403c0ad6fc7ec20f514aeba168a143aebdf1e/py_bip39_bindings-0.1.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f28937f25cc9fcae37992460be1281e8d55973f8998c7d72e7b5047d3ead375a", size = 456616 }, + { url = "https://files.pythonhosted.org/packages/c7/63/5baa949d175fcddaf1722c163f2b450ea3ea8906f3931b03e73efb403db8/py_bip39_bindings-0.1.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:332d6340201341dd87b1d5764ba40fd3b011b1f152145104d733c378a2af2970", size = 494949 }, + { url = "https://files.pythonhosted.org/packages/76/d0/11705b72d6b0c50f206d42b8af0bd9f07c3ac373ed36ab3c0779170f8308/py_bip39_bindings-0.1.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79daf697315084d1f91e865fae042e067c818c790dfdc6d2e65b8f9d119fc703", size = 457494 }, + { url = "https://files.pythonhosted.org/packages/ca/6a/f7858f0d707a821671d3d59ed79012dafad3a22ec04a6f1044094000ad83/py_bip39_bindings-0.1.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7764520c8b347ff4f3ead955f2044644ab89dc82e61f3bf5b9baa45ff03b389b", size = 472489 }, + { url = "https://files.pythonhosted.org/packages/ec/cf/d51cf3312bbc2ac77ef5928441df0b86a714148956492d88d51192adc8fe/py_bip39_bindings-0.1.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:09ca55cde30aea939c86cdadca13d7b500da414070b95fc5bf93ebdb0ec14cd7", size = 631968 }, + { url = "https://files.pythonhosted.org/packages/ed/13/55648daa439408969e3258c4e6fd0bb20998b1ac5ed69f56621926bb23cb/py_bip39_bindings-0.1.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6e4e36c2474b946dab0c1019ac38be797073d9336e4735d574cd38cc506e5857", size = 711894 }, + { url = "https://files.pythonhosted.org/packages/5c/62/70f1836c31ad0a0548142e5177f3f20fd6ef5f03481fb0b1a461789f2ea3/py_bip39_bindings-0.1.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:534609eef941e401aaba7fc54903e219bbe9bd652d02df1d275f242e28833aa0", size = 637331 }, + { url = "https://files.pythonhosted.org/packages/65/d4/c0873ba047b345ad793834eb96d003c186490a652ab8b52b0e492ef1958a/py_bip39_bindings-0.1.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:260b61bbbed75afe4f5e2caeaefa0d844650c5bcde02dadbd963d73253554475", size = 619105 }, + { url = "https://files.pythonhosted.org/packages/d0/e1/09fe0a4f7e4ded8e373857429758dd8773d5c5f456a46faf6843699cee1a/py_bip39_bindings-0.1.12-cp310-none-win32.whl", hash = "sha256:b13e44670e34e2d28d1856bba82a362ed4b84822c73bdd23f57e941da0f7d489", size = 297595 }, + { url = "https://files.pythonhosted.org/packages/f0/57/616985f9adb6008b174682f1f3c26a8736a689124351677e103c25b97c06/py_bip39_bindings-0.1.12-cp310-none-win_amd64.whl", hash = "sha256:09a1ed423242dccd5016eec18e74c80236d468ef2e85d3297615ddb4e792cd77", size = 287992 }, + { url = "https://files.pythonhosted.org/packages/22/c1/b25c23e06132731f4475e94d1313464af1fd3ade5779a96b8491b187cced/py_bip39_bindings-0.1.12-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:200ce6173c330af830177944d18402b4861f1dd1b52a410a6c02d95f69f04b92", size = 393687 }, + { url = "https://files.pythonhosted.org/packages/59/5e/61c0cad53f737293563d8c1724b79ad949e5eaedcbcbea6918ce893e5682/py_bip39_bindings-0.1.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:808f1042c31e8373bcd56be45fbebbeae2ab2e90b91178bc4d5cfad13f235f34", size = 383994 }, + { url = "https://files.pythonhosted.org/packages/8a/d6/64e8a2d7287499668531034e93459b04bb891c3063e821850b6d901f316d/py_bip39_bindings-0.1.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da4c11662304beb093dfaa24f5a3b036d4e76c21de7dafd2bd43d0e78325b377", size = 449261 }, + { url = "https://files.pythonhosted.org/packages/0b/7a/80238608da59e1ec23df49b7cd7891a7a0ef22c3693ff5263783340440bb/py_bip39_bindings-0.1.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4af354d2e138304c20fffa0820aa79f9b4ee4de3f1db4e4b77cd0fdf72c39fc2", size = 456701 }, + { url = "https://files.pythonhosted.org/packages/17/82/ee1b319fafa3abd5c9e7c4b9093193bfe645bc4eb9effd97147fe0e5de77/py_bip39_bindings-0.1.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a337fd6eaf16bf8c42752d9a25fd58bb303499da5d6428b466eff7ddb642237", size = 494967 }, + { url = "https://files.pythonhosted.org/packages/99/1e/e7c8940e097d99266cb9b5c4c40ca2e52afd27f768b3d1ec0f125b0b2ce1/py_bip39_bindings-0.1.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d72041b34d6a7ba5e83009cb96c59c48b356eb3831a0ab627421e1fcdec83c9a", size = 457601 }, + { url = "https://files.pythonhosted.org/packages/ff/28/ec02fc1bf84acbd1595d603cd7c6a2926159175cea3be1166988322190cd/py_bip39_bindings-0.1.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e48ab058ac4cfdcb6bdaefc8bb555a6d36b11673589332d6336495d388a4902", size = 472536 }, + { url = "https://files.pythonhosted.org/packages/a2/0a/22916b1f8ae4187781ee38acf3470808a1a7b5adc3f435cdd112dbb21189/py_bip39_bindings-0.1.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cbd4865d3ef310fbad03197511423376ff8fea162d8d14c4259ee086be249b74", size = 631996 }, + { url = "https://files.pythonhosted.org/packages/67/96/2a3dd14b9b7e07a5624c6cf02c66583e20734e5c5d789fcf9400c9c87bf4/py_bip39_bindings-0.1.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:b7eafc0ab28d5835789abc82d2443aec7154c0bca8b627597ab7b4761bb3d8ac", size = 711992 }, + { url = "https://files.pythonhosted.org/packages/ca/df/8d534cc41a699bf0b766aa298704fa44bd981013f9882e0330c2fb70af9e/py_bip39_bindings-0.1.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:97e739430d3b7801a4afd0e767c82554b92ba727b52c8c3a1ed9f9b676c176e3", size = 637395 }, + { url = "https://files.pythonhosted.org/packages/dd/d0/ae98b03e8f10ad0793b713b2afa723b74995f5c09dfee9d760dbb41399ed/py_bip39_bindings-0.1.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6c3a446e7cb339f8d58659bf0bbf8b549482c2eefc37c7573b84150de4423d7", size = 619253 }, + { url = "https://files.pythonhosted.org/packages/9c/f3/d6f5e73456f6bf4001bf67c0e568ab2697d1fc176cf1b0e2fc4fdea0de24/py_bip39_bindings-0.1.12-cp311-none-win32.whl", hash = "sha256:6e9c09a916ac890ea629ad8334b02e43ce7d1887426d74c7c69f82d0820f66db", size = 297592 }, + { url = "https://files.pythonhosted.org/packages/d7/81/3119950191dcc80db45cb7ddce0d1b5fd19bad49ec1e40218e72aaf71c61/py_bip39_bindings-0.1.12-cp311-none-win_amd64.whl", hash = "sha256:f3480cb2e99b7d0ffae676d2d59a844623cee4c73fbed5c9bb3069b9a9845859", size = 287993 }, + { url = "https://files.pythonhosted.org/packages/8d/bb/fc724925bdd20fd70e43a5fc05f39d1ff4b6e63e63b2c992b000d69a4c4e/py_bip39_bindings-0.1.12-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a65facd53ff11314a1e2411fced145daa3a07448c40d8aff87b22dec703d631c", size = 393595 }, + { url = "https://files.pythonhosted.org/packages/53/24/bbd57790c3780dac0d48bff43d78aaefb17aa6793b5d44ec6825e6d700b5/py_bip39_bindings-0.1.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dd1490d168409763b846df691e14756c1461b1edf62343ad72c4b1e00918798d", size = 384102 }, + { url = "https://files.pythonhosted.org/packages/a3/c4/1bad1232180de5368ddc08845e72d9bd6eb90ef135708aad08ed5692bb3e/py_bip39_bindings-0.1.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21bc7bfb907ebb4805b83f4e674dbe2745dd505d22472eefb65dec09c679a718", size = 449147 }, + { url = "https://files.pythonhosted.org/packages/8f/b8/a4eb574670d0a3840c3a20f5cc2889cec572ad83810067d7fad67e3a98ea/py_bip39_bindings-0.1.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1aa1cf5a76ea8280f2f684593f1456d8f459f200f13e7e1c351e27001310ae1", size = 456974 }, + { url = "https://files.pythonhosted.org/packages/d5/4f/b02c27f405f63c729b2bfa392044d5c182126907c360012da47118982aee/py_bip39_bindings-0.1.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:950a127bf0a71be0a163bcce16d9cbb227e80da4f12ffcc0effecd9743c806d7", size = 495143 }, + { url = "https://files.pythonhosted.org/packages/7c/6f/d91908e5967198d83993c924660b18c03eb1ea560f6539d9f376ab4b42a3/py_bip39_bindings-0.1.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7ad2ed21601f40037e912e87725bb3e3aef1635fdd84eae21d5bbb0034d5727", size = 457718 }, + { url = "https://files.pythonhosted.org/packages/10/1b/ad82b7592294ab909d514838173124b8f302d347ce4c630b7cc37bc652bc/py_bip39_bindings-0.1.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aed015ca58ae7e9912e7cead85feba9ce7ccabd6605d76c436615fbc035278a5", size = 472972 }, + { url = "https://files.pythonhosted.org/packages/6b/7c/430613e33c23b4fd883f582682afdd48eeeeb4f474c8d1e005f858ad8326/py_bip39_bindings-0.1.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5f6aab32cd3cc0fd7fb72247bada0cb269c3fc120dbdf12cfa06af1e5d3243", size = 632513 }, + { url = "https://files.pythonhosted.org/packages/4a/20/cd62358b12c07952ffe64688edf2c37558f90785e6f3f050a23ba3798080/py_bip39_bindings-0.1.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d4f62d125f9cd9a3bf183d1cc3d0ff794e78185098c61c6392221a00e15dc4c7", size = 712629 }, + { url = "https://files.pythonhosted.org/packages/13/ee/e1752b352c79a42b1af500bb6fe251e41782ce55d7d76be8d40f9f5b7f38/py_bip39_bindings-0.1.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:25f3f6ab788d14a56691cbef8ad3345040c358fced832338b81fb87e9951ea5e", size = 638350 }, + { url = "https://files.pythonhosted.org/packages/9f/fa/02c2d18bebe763057b9dffb2d6a5be03f633bc6e3316e9ebeb0ebd40ed22/py_bip39_bindings-0.1.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fdf3c4d3acbb772c5e90da1f24db39b889d9e69b442925ebe56244a89fc24f9", size = 619254 }, + { url = "https://files.pythonhosted.org/packages/b1/9c/065d10300d3ac983300e398c33261d39935d77908c9a7c6bb4a110c75095/py_bip39_bindings-0.1.12-cp312-none-win32.whl", hash = "sha256:c7af72b8afcac625d69acd40f714963725d8078bee57c36844ae1b924d6490d2", size = 297450 }, + { url = "https://files.pythonhosted.org/packages/52/22/fd753b852d46ef18919df826771a5a7e4c5660e2afb6424510634ce3e454/py_bip39_bindings-0.1.12-cp312-none-win_amd64.whl", hash = "sha256:1dedf9899cb9cc6000373858ea9d7069ff4d961d4c53f6624496ff31fb4398f8", size = 288392 }, + { url = "https://files.pythonhosted.org/packages/e4/07/c854e75005e619e4d553b98608f44c9e337a664102467e696567994806f0/py_bip39_bindings-0.1.12-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bf359da1ac1648f851754ddf230ab228986653d87af7ade00e11d7ee59feba14", size = 393599 }, + { url = "https://files.pythonhosted.org/packages/dc/c3/0817235a0e1bc45bcdb87c2aa7482d2a563c72258d61af8bbb1c29244120/py_bip39_bindings-0.1.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:596c266afc617de543153ee95184c1ff54e355194a44bc0be962798a197cf367", size = 383960 }, + { url = "https://files.pythonhosted.org/packages/4b/7a/13ae427d86cded7bc8038bd5b75a1bc5b4a376e91a0eda0368c46a0d7c72/py_bip39_bindings-0.1.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a524054b860730d76b4bf81a3f71ea82e1e74bb0dd5192019b06a31c80393e1", size = 449080 }, + { url = "https://files.pythonhosted.org/packages/71/10/8b253dc82bb28ce787571d88c76e9be209a9c309573f065c5e5ee35f99f2/py_bip39_bindings-0.1.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11c43577a8a5cc55e88b07507fd9bde7885b948d1319c3850945b135a54b4285", size = 456628 }, + { url = "https://files.pythonhosted.org/packages/14/b2/52703b6d8f6d73dd7e7f041ea573cfc3dd4ce3a7e25527bf6ef55c34a3e7/py_bip39_bindings-0.1.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ee82d050e97cce6ac8298bb77119e9aaff2a51feec07e6682fd3b8dba405cf7", size = 494768 }, + { url = "https://files.pythonhosted.org/packages/32/d7/fa2b10ff15d607f7e0d18ff1585a25acba87254bc7a54f67e5f50314302f/py_bip39_bindings-0.1.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ae80c05dbe60d55691ee948927e80bef4e846c652735c639c571578e1686c1", size = 457439 }, + { url = "https://files.pythonhosted.org/packages/10/d6/64e9b2d66a0c616eb455a46b49b71bc9935f8a855f96f431b40efd230f83/py_bip39_bindings-0.1.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3999ce6d43cb3ea9d23b41883f2284326647604a91dd23030973d345691838f2", size = 472408 }, + { url = "https://files.pythonhosted.org/packages/df/60/fb1c2d260e04fd1a0f1e33b3e3e155bd79ccf09afcd829623c81c61c3412/py_bip39_bindings-0.1.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6d0b160e9999e331e574135784136f500924a36d57d0c738a778b09abc36a495", size = 632175 }, + { url = "https://files.pythonhosted.org/packages/5c/a1/f2ba39fb8b92beb8596d2f0513435e1eba3198a9aac76d4b5d563f884880/py_bip39_bindings-0.1.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:8c202356183a467307930a8da21c6a1e6a2a4ce4841805dcfec0629229265ac4", size = 711810 }, + { url = "https://files.pythonhosted.org/packages/18/e8/e9a38f2ea60f0d9b575d8f7b5fb70633830b258de645a52a14d4b4bac41b/py_bip39_bindings-0.1.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7b0f6f92da76fec954c3199ff94c6ae080e174ee33b7241fe75d921d5c9954ef", size = 637303 }, + { url = "https://files.pythonhosted.org/packages/b7/d9/7b32e60d201e3fe36df8c20b717e417dae8ce47a9e322d951ad032c6a33b/py_bip39_bindings-0.1.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6fef2cb2525609d2881685e5ea383d93ba1a1aa2e8c2d94fb72d8e005fafe70c", size = 619208 }, + { url = "https://files.pythonhosted.org/packages/6a/1f/f55e10063df4bf98478c14db3d78beb4f7cd868ddff37b3f7b045fc85676/py_bip39_bindings-0.1.12-cp39-none-win32.whl", hash = "sha256:89b7c4a1194dc2b1edbd05532d6ba193ad5c0ada03d5a0a78744ef723007ceb5", size = 297575 }, + { url = "https://files.pythonhosted.org/packages/46/90/50cb4dbeb69f93529e1c684e10cd1304b5435ecaab6c81988329f642f294/py_bip39_bindings-0.1.12-cp39-none-win_amd64.whl", hash = "sha256:43d831223bc76cdee33ef5668a736db098a0c20e80f9e10bd2574253ec8a5e5c", size = 288101 }, + { url = "https://files.pythonhosted.org/packages/71/24/ab48e19a9769d01996a225570f2b1f0600fe0a62adbe77713356ea2de923/py_bip39_bindings-0.1.12-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b60e46ecd3bee23f4e458303ace7c86c592cff2d28860808a5e46398f915035a", size = 449305 }, + { url = "https://files.pythonhosted.org/packages/15/14/597ba2bb300c588da62cdcdceba5a5a1d31c35157699c11e8e6dbd7f4c28/py_bip39_bindings-0.1.12-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:71afa142cf045b4d7743a96aef66f030342a8f287a83733c6841d3b005954c52", size = 457324 }, + { url = "https://files.pythonhosted.org/packages/e7/8a/115dbfd71a72739b6d6b68a3d2fc2c2e6a5c8ad8ebf20c73f18f1feb1f9d/py_bip39_bindings-0.1.12-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c65ba92ec43ef78c5926506437b62d959ac4e343f8bf2cfc8ed799c3a6495f23", size = 494969 }, + { url = "https://files.pythonhosted.org/packages/62/6c/7d50300b72c03ec63af8e1ea997b448ef8cf2f1a9393cb243b3a7dda5289/py_bip39_bindings-0.1.12-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf3a5ec5095f56dbf0ab8258d722d860746e807c5ace99ea5ab92000268a750b", size = 457309 }, + { url = "https://files.pythonhosted.org/packages/ae/dc/42ff2c5228a5fa5897a26fa58f2e9973625b91931fb34730057d26fa2ae2/py_bip39_bindings-0.1.12-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6232b0b8dfecd73bbc4dc4865f1c0b10d00df63dc19ad7448b5e5e45fdd279e7", size = 472550 }, + { url = "https://files.pythonhosted.org/packages/c4/18/af32c6fda144e053c106b52ef7775035f9ec981bd4987f66bf13c78e14cf/py_bip39_bindings-0.1.12-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:fd13f3ba45ea56f2db85a66c1d8b03337ec8977b0a00a02448f4f65112638177", size = 633101 }, + { url = "https://files.pythonhosted.org/packages/81/a9/15fdabfe8d0a9e14d0570e6c2b3d9e6144166dd82d76206f68bae4968c2a/py_bip39_bindings-0.1.12-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:bc00a31943d3d6d6a1ab61321d0c14675f4f1452165ab712c90c8368f754648a", size = 712410 }, + { url = "https://files.pythonhosted.org/packages/38/e6/03c897d0c87c48f1d78a1fe15276891f0f603d94665d55aa8d250a250af5/py_bip39_bindings-0.1.12-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d9f96bb10320a1ddd354ea639c434cfb1e594d4a1cb9425a476f06fc04aa18d2", size = 638118 }, + { url = "https://files.pythonhosted.org/packages/97/89/d65013ba2cad7eb43e439a4b274b10b208a933e723e71ee390b817966e34/py_bip39_bindings-0.1.12-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e106a1d6d1106cf40a49b3e17748c89fd9561a3aeeb98725dca9ce751c780e16", size = 620020 }, + { url = "https://files.pythonhosted.org/packages/14/c8/1bdea49989901a3b06a33bdbc51d0792701199a213e4c5b20cea6719574c/py_bip39_bindings-0.1.12-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0222bc5d439151db46a00cba51a4d4b1d4bad453e760f0904b506e296c5d7b5", size = 449130 }, + { url = "https://files.pythonhosted.org/packages/8e/71/8b54c97909a79aadb066d22f4f3649fb2ab43e2cd0982504c680da186a91/py_bip39_bindings-0.1.12-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:451217d29b37c0d168b1dc4e9c29d0960ffc0d1857e9dfe9d90089c8044820b6", size = 457341 }, + { url = "https://files.pythonhosted.org/packages/26/b6/88305e0dc6c3c87e5c0d38d1b873bae9c2a9b4b445019094ba38b6e3cea4/py_bip39_bindings-0.1.12-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c012eb605dd09d2d161438bde8dad7d75c13a8fef7ecaa5f463f0dfd2e1a2a8f", size = 494927 }, + { url = "https://files.pythonhosted.org/packages/0d/44/f0c83c74279d48762c54aafab0ec37db2cdc65d464e537dd9e559620d135/py_bip39_bindings-0.1.12-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e0f85a2a460a8e7241b42e3caba9a5afc3ea6e4d47c6dd39d3d490583418cfd0", size = 632989 }, + { url = "https://files.pythonhosted.org/packages/97/47/9169bf36eb4e98145bf04feead3567b3a3df0a47d83cd926c2fc6f1dcdd3/py_bip39_bindings-0.1.12-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:436bae87732b90eb315845a95a41446dc0e5dbe77ea6c018b28d2b73a489ef04", size = 712397 }, + { url = "https://files.pythonhosted.org/packages/b8/ee/bb9947fce727caa1b7f3234bf4d8b5d85952f5c9fd4ffb7f853b6f519c22/py_bip39_bindings-0.1.12-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:4d6c13fb07cd7d4068fb2a82f91217d7ea8962ebbeffa88f9aa57e4d24b38f0c", size = 638114 }, + { url = "https://files.pythonhosted.org/packages/17/ad/35d179d2c6b9d43236ea2a9750716382c8bcdc2698554ec667c8fdc99784/py_bip39_bindings-0.1.12-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:bbe75eb05d5cadbb32cb6db0d0af53fe2c64ce70121e2704111ada8575778255", size = 620029 }, +] + +[[package]] +name = "py-ed25519-zebra-bindings" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/f5/833c284f7d76e13d9520215b5731be2983f8f04cf3405f087267de89af37/py_ed25519_zebra_bindings-1.1.0.tar.gz", hash = "sha256:2977603b59cfc593fb01284465fe41062d6929b0d09edf0e1ade40709977014f", size = 12176 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/09/7fe63ce6765e5eb404e3d755e0cb919f99b09e4d43e7107a4194d5f0d0f3/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f0634c6b56cd81ce8bc10c322c14a7cd2a72f3742572c0dec332979df36e7cf5", size = 287564 }, + { url = "https://files.pythonhosted.org/packages/be/5d/c46810a5df49f110249f98b489f05cc19a71fc6636a3be577cdbd40581e8/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc91befe939088aedd176e46f1316b46b4c5dd8f44a14d309e49a634fd65dbe7", size = 263660 }, + { url = "https://files.pythonhosted.org/packages/62/53/fcc08b39dc2821a785addd08ac2823ab42fc0c380e3c93a7b166ac42a48b/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70cc6b1d460608b23e7a0f91ecb0cd4d8ed54762fc9035cc7d5d6a22358d5679", size = 295682 }, + { url = "https://files.pythonhosted.org/packages/7f/69/5d494066033b1f6d7eb71f9f258161bb32e811226985d39fc73c9cbc671b/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:045396583efc93f16ee80df7739040a66cc7f8e048e9aec60d19e4cd2afaafb8", size = 321290 }, + { url = "https://files.pythonhosted.org/packages/66/15/2e09d120cc4e01340b17946d9dfa3c56f39e09f83b4197ffe9dee5a1e104/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:838ea2bb3f27907ec7a07aff6b267646b7c0c010f506673cbbc0d911e57cdfb8", size = 334955 }, + { url = "https://files.pythonhosted.org/packages/da/97/64dc445584317674293137e2fca9e663430f704df45cf534e652662c8336/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:716f090ab1564c9bf13e790b6f8bdea5ae40b68082def48f91023a8e12e38cf1", size = 316651 }, + { url = "https://files.pythonhosted.org/packages/15/8a/4f438c5e73e24cb2e07f82a3b7f0bded1ca6a7fd1233e2d971257acac97f/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2ebf8935bf1a856d9283916cfa62083b5cdfb24f7b772f42276fbf5b5af0f1f6", size = 334219 }, + { url = "https://files.pythonhosted.org/packages/3d/f5/edfaca7bf003d5ed230e27265fae53acc7db8030699a257e9a1172363602/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a9e5652d3bc2e4e5ef7c12ba6767800b49f9504207e4210ac4bac9c2e31efa9", size = 481295 }, + { url = "https://files.pythonhosted.org/packages/0e/b7/dc55f832301eff0309c14f8ebbdaa6e9ba75b405c2299bfe25c6bf45bbbe/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:b846ffdfd035206e16e76026bc1f4cb45964068a929b76b2ec3289fef3ee420b", size = 583531 }, + { url = "https://files.pythonhosted.org/packages/a8/c7/9d22c11bf0816133010e6647f9dd332b0e4ad4f871e08ee6de2c7f0ea486/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c97c0d04be12b299581daba0296bd522460a0f7001b9340d1551c0e2daea18a4", size = 506908 }, + { url = "https://files.pythonhosted.org/packages/93/81/f9e6a1c070d779ef524de7ebe09eb392ba7f9829a744e7b217d843cba46b/py_ed25519_zebra_bindings-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1d8f8b04c2b3372ef33554d62fec44db28517dea1986944fc65ce3b35341800", size = 485847 }, + { url = "https://files.pythonhosted.org/packages/36/08/f9e29e81266b2686727877e70cad4279b4f1552eca5f338c25a25d9bc025/py_ed25519_zebra_bindings-1.1.0-cp310-none-win32.whl", hash = "sha256:3243cdaad41406c21e3840630ca46a997f30644a7b3c4aa7fe54c930d0ad66af", size = 183850 }, + { url = "https://files.pythonhosted.org/packages/23/68/1ff28bc4e2962a6a89bdb75b308ed9236b3b7947364ff89381a2f596ea1f/py_ed25519_zebra_bindings-1.1.0-cp310-none-win_amd64.whl", hash = "sha256:278481a18225dc74e4292980c1859b1774b9e86da2d9a4cd63988717d24d421c", size = 186785 }, + { url = "https://files.pythonhosted.org/packages/95/95/ae7129025ffc3954994b0bd72c83a091ec1a96a508da2b5a8f3e9e54ef93/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:048e84121007b6ced32b70086e9bd710a825920f0715d73be4760c45f61847be", size = 287381 }, + { url = "https://files.pythonhosted.org/packages/46/9d/f41a6b8103697eca40c0bb9b22c8bd9f9593ed1941da340ce27b419c2d6a/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8200479a222da9bab0abbe35d9a60e4f658a4039054c3b9f2e58a102a393a658", size = 263398 }, + { url = "https://files.pythonhosted.org/packages/fa/38/5edf90bea230aa9528f581b5540f994bba6bd517ffc1a902d44fdc46fcc5/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ef039b7a7e4f1653e7f0c467d136a7e135061e53fdc74934d36489a8859f9e4", size = 295474 }, + { url = "https://files.pythonhosted.org/packages/ab/76/79e2a9e3873b7f99b3071a3f2473d7355d47adfa576843fa084bfd1e66e5/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d6d035b7bd3dd998ef6030666e69cde95c34225187f53ebb9c2fa7298a65ffde", size = 321097 }, + { url = "https://files.pythonhosted.org/packages/12/de/5aa80345871578a23d548f03597cab77ec7269434136a0e1f716f7222355/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f4a7bb72294f7f1f560a464832c0fc32bc0a20cf4d3b638f2428bf3dde6ebda", size = 334803 }, + { url = "https://files.pythonhosted.org/packages/a1/c9/a6819824ed0bea5139d3b85eb51343f2f00dcfc93cdf3829deeac8b63fc9/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89735c2623bcf02177004eaa895250a3115214cd51df2ab561863f565aa06b1b", size = 316386 }, + { url = "https://files.pythonhosted.org/packages/49/c3/37d32d12e36226f6ffb3d5f68e2191e56b708bfc39662f67e1ff7c5244ee/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4a7cccd8ab3156d1f397c6476583e78427e93cd01fa82173df78b96e15eb9f4d", size = 334029 }, + { url = "https://files.pythonhosted.org/packages/28/82/82e787a9899a02154b7db6f73c3fe9d5f414baa45e3f4dff00362750473f/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:27483aa9262d0952e886d01ec174056503238064ce1f08a3fb17752db18071dd", size = 481082 }, + { url = "https://files.pythonhosted.org/packages/d8/a7/e37725ae7029482742ce77887636a1051c8ba4667c84dca53c78e631d2e2/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:b461baeb4adb5c5d916f8cf31651142744f29b90f010a71bb22beafe0d803f40", size = 583309 }, + { url = "https://files.pythonhosted.org/packages/89/e4/568c2134ebe3b95ef10c0d00da28a8a667aaa2cf913f2b8436a7080f8036/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1b79af368be80b5cd32b2a678c775f113c1d76c6f0e1ea5e66586c81c9e0ab5b", size = 506769 }, + { url = "https://files.pythonhosted.org/packages/08/06/1afb277b1021cc0669b56fe7cad81b5f26f6cded280f1b2f881ac6dd5f54/py_ed25519_zebra_bindings-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9555ccf645374e5282103416fe5cba60937d7bf12af676980bd4e18cfa2fab48", size = 485460 }, + { url = "https://files.pythonhosted.org/packages/21/82/576d2c725d6fb66090424ad30eae9b1a503cd07973b6bc10c1f28a508686/py_ed25519_zebra_bindings-1.1.0-cp311-none-win32.whl", hash = "sha256:1c55a32c2070aa68e0ed5a2930ba547fbf47617fd279462171d5c0f87b00df6d", size = 183764 }, + { url = "https://files.pythonhosted.org/packages/2f/ed/1da5f72b31eda77d6333756c6f4c542962ab6071a192e3bf4db0ca1e4ccb/py_ed25519_zebra_bindings-1.1.0-cp311-none-win_amd64.whl", hash = "sha256:c4a4dedb1b8edf7f68dd8015f9d8a20f2f0ecca90fac4432e5cbabfcc16ab13d", size = 186734 }, + { url = "https://files.pythonhosted.org/packages/01/e7/41d2c8c43d173e3f5421dbcff89ddec60f3b0df2111146a3469be8f0b19f/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3ee9a0b7eb896547e539a27c4286461d58c6a99952ea27fa1b5f5e39e63019dc", size = 287118 }, + { url = "https://files.pythonhosted.org/packages/81/99/4dd0de0907eb44e3bb4240dd5daa002ab52c92a44f288cb8485e1cd42534/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93e2a12d0bbf58f4d1e5ae2a1c352e43302cadd747a1a5e88fea03ce7a78a562", size = 263119 }, + { url = "https://files.pythonhosted.org/packages/99/ea/46d2ffbe8205c02228106ff757bd1afebfe1258f8ded83303ed20c689499/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33673e6047eba0a0a28e818fa0b36b703986347fc98e6f0f96e36af68756787", size = 294870 }, + { url = "https://files.pythonhosted.org/packages/ad/6c/767881f4917b7626a1a1e5ad80b031a692883e93076c361254f20bcf3964/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:14399e6e8c5b9c193256a1b9aec16b9de719691de84ab23a690056cfe011d13b", size = 320685 }, + { url = "https://files.pythonhosted.org/packages/1a/4c/4e730ff1c965bacd6a6a065cd4e462d37ed938d172939609a5da01bc03f5/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85ea7a5632a1bf6713518bb56d4c8abe5128aee173a3c498b3a564cfb346ca72", size = 333754 }, + { url = "https://files.pythonhosted.org/packages/bd/5b/b889db7a23724ac1c559c7079c7a941e822849695109aac1d065251039ff/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a01f58a1c980df68c8efd43892562b3224507bab83d880910fbb4a3c84fc965", size = 316045 }, + { url = "https://files.pythonhosted.org/packages/7f/3d/ba457c149c108d594adea964573f2b4809fd3b7ed887a7d38aa77ed7d11b/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:655360cd74718d4efb8fbaf7afb2e4ce459af5f1d399479f577a63bd9177aa3b", size = 333567 }, + { url = "https://files.pythonhosted.org/packages/88/00/f4e05b36cc04212c4d00c6fcbfbf17a2b15f6d08f00f12c1ce499061b666/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:650081644c6613fdf658456ed4b2a6580ec1b54084f318a31a924ce5cf536bb9", size = 481375 }, + { url = "https://files.pythonhosted.org/packages/be/7b/e96f39dfa9fc11e477256b3dec80b7afde51004ba97f87ac2eb3e68e44cf/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5d56b81186fc75cbcf80d0549f83e98c62c4359460e512f9fb8d6c7be2a158dd", size = 583169 }, + { url = "https://files.pythonhosted.org/packages/ca/8f/9dbf2a43efdfd2b2452eb497b3a72bbac40c2fa57afc6262574cd05ed7ae/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:072bf62421ad890c1849aaa19c7b6e6a890d337f0622e9bd09161b180a10496c", size = 506486 }, + { url = "https://files.pythonhosted.org/packages/28/ca/2bad513face5cce85773d9ecf92dfe8ddbeb8ef33d64b6c2a14565cc99b3/py_ed25519_zebra_bindings-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e09830c3672699f5f1f164fe92b102254ef68300ceaddc847d9a35bf4a2ec270", size = 485075 }, + { url = "https://files.pythonhosted.org/packages/f9/18/ebc4dcde6da7f6a5040bf4c53fd53a5942500e40da8ff3179b8e8462f62c/py_ed25519_zebra_bindings-1.1.0-cp312-none-win32.whl", hash = "sha256:33ca2a7ad10846c281a73450316b390c7343e62e40516389fc1b580241f3907f", size = 183761 }, + { url = "https://files.pythonhosted.org/packages/4f/17/e334d38d2ff14fab0722e03959472b6e24740376ae92bc30c9c076af2be8/py_ed25519_zebra_bindings-1.1.0-cp312-none-win_amd64.whl", hash = "sha256:4ba042528ddb81f8f025b1987bf8f19547f188efb7aa4c95d1a4e3e7f968e991", size = 186542 }, + { url = "https://files.pythonhosted.org/packages/78/16/94ff2eb1f370eaeae197fa7346bc5deb8f490ec8153a17bb9ee4e6eab49d/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:d75a61407651174841051d59ebcee5716207371999bef78055193e96b6dec546", size = 287470 }, + { url = "https://files.pythonhosted.org/packages/0c/27/dd738d247c2100ce5af3f802fe237a5ef4741f68e7baf861ae60ab93275a/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b5afba0bd4ae86f06b278698d24acebe2d4b912e0490c94ee550a859377e5c05", size = 263676 }, + { url = "https://files.pythonhosted.org/packages/69/3a/f24944a6c3d9bb16688d866d8d255267096b5bf5fedd3f8ac3f0f2bf310f/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d977fb8d7f5594278ea3eb8283dac811cc35c925176454ccbb3ddf0110e194fa", size = 295236 }, + { url = "https://files.pythonhosted.org/packages/25/ac/fa52975b53d9fea764cdce92ae82724444f8aad252da001a4673ecc2ac13/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:83aa29a0d0df233591da3118142c818adc3f697143d655378ee076e6f091be7e", size = 321339 }, + { url = "https://files.pythonhosted.org/packages/3d/f6/548100f5acd73e41012de260050232c1cb5e342061a319698b0d7e01b0d8/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01f2952e5c7082dc9266d668528b27711874d0f5d2aa2e85994a46643b12686e", size = 334574 }, + { url = "https://files.pythonhosted.org/packages/a4/f1/3839116a19286b70dc833f53e0f91927426d1f0760dd5e1fb147ed29a85d/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0db1e886f65a439fe9641196e05229715701df572a92b41428ad097d4889c5b", size = 316200 }, + { url = "https://files.pythonhosted.org/packages/f2/ae/d960505cb54f6059ae85291e6943cd41a38d68d2e42438e26bd6df0b6a2a/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dada974b078204d1591851d0e5958824569900be3ea53676b84165ba16283641", size = 334148 }, + { url = "https://files.pythonhosted.org/packages/c0/83/929e998cf18544b1e4065729b7144814777580da6d1450b9b2d71a06e2bc/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0f7aa0056c7af9df6c580880948cce42f779951e3e551573acf9b30462d9ca9", size = 481688 }, + { url = "https://files.pythonhosted.org/packages/7e/6e/f5a3a290e6cfc608662b4082573bd50547f8b9338d8db3b8f286082c5013/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:2176111de560441caaf72f09da77a1d4f8eacbb34245e2531c7243ee4070829f", size = 583432 }, + { url = "https://files.pythonhosted.org/packages/0d/f4/32a5359a37e05375bbe92f574faada30cd3c84636d47405697fe39ece30b/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6f8686f160c4e7e928c79ad33919817b9eb608e5808154311a933078bad243b4", size = 507002 }, + { url = "https://files.pythonhosted.org/packages/d7/72/e7c8db182f54fda23284017a8b04dbf00e0d9a6ce527c5613d73c092be46/py_ed25519_zebra_bindings-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:09b089af355cb0815cca4796407f89aaf08aceb5d39c5b7de087533319e3673e", size = 485723 }, + { url = "https://files.pythonhosted.org/packages/c3/13/31a5ee9e9fbe2a7ed5395120eae32e53c339219bb2fd8b342aeadd5ada5b/py_ed25519_zebra_bindings-1.1.0-cp39-none-win32.whl", hash = "sha256:12e5f602897c1c95217e406d80f2e7901c90b9345011c147c36989bfb7c3bb49", size = 183803 }, + { url = "https://files.pythonhosted.org/packages/f6/0b/b1843c6a0e31f6e0bf35fe0aad6c5e3070894d867974c47614bdb5210c13/py_ed25519_zebra_bindings-1.1.0-cp39-none-win_amd64.whl", hash = "sha256:119c3ca0c23570ead0a3ea9e8b7fb9716bf3675229562a7dadd815009cecf3eb", size = 186707 }, + { url = "https://files.pythonhosted.org/packages/56/94/c4d6afa181c4e6e36b1a216e5bd9bb795972e7905e609e1d81a0c2bcf626/py_ed25519_zebra_bindings-1.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ded8debbcffc756214cd55ebefff44fb23640c9f54edf34c0e43b371e2d2b42d", size = 296429 }, + { url = "https://files.pythonhosted.org/packages/0e/d9/2292f1e3f99cc617a15bc02b560162a1fb9ed18584731dc4840e250770d0/py_ed25519_zebra_bindings-1.1.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:db18ef79ea6dc0bc42e28cd46eb442d8e84c0c9c8b2809babd63608efe015ec9", size = 322175 }, + { url = "https://files.pythonhosted.org/packages/75/03/1825ebb00307727465677c5c4c8b4a651da86e7d004ee139b6d1e51f375f/py_ed25519_zebra_bindings-1.1.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:875bba860c5ce874e33e6d04c4804c8e4149754720bf47bd66c068a61c2ed3cc", size = 335359 }, + { url = "https://files.pythonhosted.org/packages/d6/a2/e84d49cce3e2154c6cd65b66609b5ac6302166a8278ad149dfcd1921d0d5/py_ed25519_zebra_bindings-1.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de987c5c8b3a69504f82adc4d3b70aa322315550f945684111d8bfe40288517b", size = 317462 }, + { url = "https://files.pythonhosted.org/packages/35/9e/c2e90c903bab03d254820f48eaaed31e60a4176fc249d232f7583b677ed0/py_ed25519_zebra_bindings-1.1.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9721c029279a6e074d4a69a8ca2ee5da6264efda052fe07afcae6ca04e340805", size = 335011 }, + { url = "https://files.pythonhosted.org/packages/1b/d5/2d63a6a53ee284fbca56ed6ad121fba8336551cb346445dbc4339444bdd5/py_ed25519_zebra_bindings-1.1.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:b8843fe090b793449fc8b581ff5d55c03ae9bb18ecd4943ef27c51751df9e5e8", size = 483098 }, + { url = "https://files.pythonhosted.org/packages/79/b4/5138793a19067cd0bf7323e9e90ea161b881582130a0e304a282d589d10c/py_ed25519_zebra_bindings-1.1.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:b8da29729eb83c1aeeb80f0a60ceb30f6c00ba9c2c208548f6628b8f4764eccd", size = 584363 }, + { url = "https://files.pythonhosted.org/packages/0d/5e/833aeff1ef175cbcc4e45fef0e11601c55ce168c4af4ef9a8504f169a4c6/py_ed25519_zebra_bindings-1.1.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a99ab59da361a9834c0019954e72a7687fa19a3380c5acc3274452c26af3b791", size = 508221 }, + { url = "https://files.pythonhosted.org/packages/3c/9d/d9763cf45b8e7c24adbda9d537d771fb920335c92d39abd919b14f13ad69/py_ed25519_zebra_bindings-1.1.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4b40b19b0259412171a36f51778bc9d8e92f21baea469549a03ff99318bc640e", size = 486448 }, + { url = "https://files.pythonhosted.org/packages/18/2e/cbcf817750b6f925023edb278bfc57da139fe257c11007ed43928d78992f/py_ed25519_zebra_bindings-1.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b7c389eee3f99c1ad3b3fa32fc53914dda22876f8e2918b5b564b98f029dd92", size = 296509 }, + { url = "https://files.pythonhosted.org/packages/db/37/4db916db2f621d6387ca056e2de7e0b3689887e0b0dc09a33695d46cf2d5/py_ed25519_zebra_bindings-1.1.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f13dffb7875eea6b2bd8f9b1165e29d9cd3df2c919c2f2db0f164926c99393e8", size = 322128 }, + { url = "https://files.pythonhosted.org/packages/92/ba/dfa605a4c32faa09ba2f6a914901fcbee11984ad03e6fa8d3d40ae97c050/py_ed25519_zebra_bindings-1.1.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a55f043d87e00e7d68fed03d02ac0725acd2dff9a03e61388285d6d920f6850f", size = 335521 }, + { url = "https://files.pythonhosted.org/packages/a3/85/18fd9675d94e08654b5acbbcc7425ebd09ad007d59501a983e35b0828370/py_ed25519_zebra_bindings-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e48f09c403c58245cc6712ce34ba3cab91705c901a6c4bb1e865847f46b26ec9", size = 317439 }, + { url = "https://files.pythonhosted.org/packages/a7/8a/f2bf98ed5e4c3c3eee41acf3f0d1aa98f57958642976da5d20badbe9600b/py_ed25519_zebra_bindings-1.1.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17694b0afce037860043cf8237a990e8df9c307b4decb73028d794ae56733875", size = 334991 }, + { url = "https://files.pythonhosted.org/packages/5e/1b/2252399cb249a522bfe696422733765caa509ea14b84419cc45fd11bc555/py_ed25519_zebra_bindings-1.1.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:c80f339abfc522248c749323b2cd6d555c3095128b01d845eb48a746318553da", size = 482965 }, + { url = "https://files.pythonhosted.org/packages/e0/ea/128febcf785b280a56892a68ec331a37d253e8e81dd4a2d3cd9b15641b15/py_ed25519_zebra_bindings-1.1.0-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:89222bb4e16d1e222a95c622630f3380fe1896ab7d0cd145da39f3aa8888ed64", size = 584453 }, + { url = "https://files.pythonhosted.org/packages/b8/ae/38b49924c59a5eddfc8892ed93aa6b3bb2bba7f31dfa94103350a56400ee/py_ed25519_zebra_bindings-1.1.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:85904f3b4e11d2fc7358686e15c1e0e3707b4e1846e82d49d764c9c44881f2a3", size = 508081 }, + { url = "https://files.pythonhosted.org/packages/d1/10/09692dff7a0f99143cfb0d782d27e4e923eed0257469657b41a64cff3f3c/py_ed25519_zebra_bindings-1.1.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:b4452e9ed752db2c1ed2b7c74e1d589dfa68101b04c3304ba87a3cb843d34306", size = 486247 }, +] + +[[package]] +name = "py-sr25519-bindings" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/55/e5c27d1387f6cb3a6bf7714e1e0c4a62edc3b006710e2d081e8bdfa4123f/py_sr25519_bindings-0.2.1.tar.gz", hash = "sha256:1b96d3dde43adcf86ab427a9fd72b2c6291dca36eb40747df631588c16f01c1a", size = 18439 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/bc/d9c0e997def0884b81ef2fdea5f3f65fae0974dd60ca0639ff0eb04d5ae2/py_sr25519_bindings-0.2.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10489c399768dc4ac91c90a6c8da60aeb77a48b21a81944244d41b0d4c4be2f", size = 331167 }, + { url = "https://files.pythonhosted.org/packages/cd/33/1d9d0345a7c71b6296927f29fb6500e460187c381d7d4fffa57e6ab1f77b/py_sr25519_bindings-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8358a7b3048765008a79733447dfdcafdce3f66859c98634055fee6868252e12", size = 306032 }, + { url = "https://files.pythonhosted.org/packages/68/61/66811bb11031a48c54b7cdfaf75731e86cf136449a10ca3287e9963092bd/py_sr25519_bindings-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:202af5a516614907ddaef073104ae6d0a98ec96743d11cb87faa09d2b235a6b4", size = 340111 }, + { url = "https://files.pythonhosted.org/packages/4c/f0/a0cf86f6b424303c1ab51e55470006da83950b39c35716e9206f2260882e/py_sr25519_bindings-0.2.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0b0d977c9ba6063d7807dda84264f10b1951736ba528b4d4078e5c9989051b1", size = 367989 }, + { url = "https://files.pythonhosted.org/packages/f5/8d/0053fb7afef406ba3aca08ff51d0c0afc31b3c7a3874c824a92c0a5366e8/py_sr25519_bindings-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e6c46cbbb87eb9db3c7deebd71c296d67c0725d9379ee737255e22c15c64bae", size = 384040 }, + { url = "https://files.pythonhosted.org/packages/a6/c6/59ba7e7edb8e496ad8ae2777d102cacb41aae7d5fb05c2ed6972fdd0d55f/py_sr25519_bindings-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9368e9ca0bc1c967db0dd5cfc401f23d364064e99a48d21ea12a068612ccce7e", size = 365611 }, + { url = "https://files.pythonhosted.org/packages/8f/ca/30ab71b4357e9380b4bd8ed65338cf9ec36970798fe8b8e0f3273c3aed71/py_sr25519_bindings-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9f1ade92569b0281ff24476bd93333865370d86746b2d7949545f1ca70ac4e14", size = 385332 }, + { url = "https://files.pythonhosted.org/packages/15/bc/1846c1600eb2004e49bf7bd07fbfcb73c61b8f17d5ab6478874b1abd0d94/py_sr25519_bindings-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7286da1662afc300038441620092a0ae527430f7c50b0768e826d46893dd5095", size = 523820 }, + { url = "https://files.pythonhosted.org/packages/b7/8b/bfd727048597181a83cc43282a61f9d7eebc1aed317e4999c58763cdf1dd/py_sr25519_bindings-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1afbf451ecb78d5a1fa3be0f1cafb914aa2d4464ce15374bbff495cc384b1947", size = 627704 }, + { url = "https://files.pythonhosted.org/packages/23/87/fd02d1a53d9287d31ecef4842cfe7df84377a797c297d8497052fa9f5068/py_sr25519_bindings-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:873c0ec12fed805f4086e36ebbb673c95af09e4007ea66d5a9bbd2cc29dfa076", size = 551535 }, + { url = "https://files.pythonhosted.org/packages/14/86/7054e137d105de5408c2510c0d457b69756cdd4d4fbdb77aa2ba71b164b8/py_sr25519_bindings-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5917f8584cf6a81e32f03547d9fbd8c783db2372d49bd9ff8c5c57d969ea1039", size = 529596 }, + { url = "https://files.pythonhosted.org/packages/b0/ef/6701c33c8f243dfc143e55ead788727b1d99865915fe82e72019dfd16109/py_sr25519_bindings-0.2.1-cp310-none-win32.whl", hash = "sha256:09f184393e01d0d2b62d3782a6d18dd0824a225444e0171c08e03f8cf3920e7b", size = 217893 }, + { url = "https://files.pythonhosted.org/packages/70/9c/bca6f55663f573eee619a2100af35797449362e906316e01b8e5ddb612f2/py_sr25519_bindings-0.2.1-cp310-none-win_amd64.whl", hash = "sha256:2d548a8ea057c6f150572059475761101ba8ef15e3b349d2d0cb108652f6aaf8", size = 224183 }, + { url = "https://files.pythonhosted.org/packages/b7/e5/62067ff055a940bcbb02467f7fb63fd85a89cc12153f8c78199ce5c71fb9/py_sr25519_bindings-0.2.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4941e6e0e180f7e72565043ed3ba7190455c9feaa2ab9ee6038904f2b4bb6c5b", size = 331203 }, + { url = "https://files.pythonhosted.org/packages/0a/6c/48a6e1289012b4ab704ccec5315a7c1f1694909b5cc332a36ec87ab03608/py_sr25519_bindings-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b63d7cf5bb4d9b986d7f7012c80b92be70311dc9b75862f7880e03b71a29543d", size = 306083 }, + { url = "https://files.pythonhosted.org/packages/e6/da/b7ab72a15e950779edf376b344b6de43aacc7250e319ff23996ef96cda5b/py_sr25519_bindings-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6752bf3b109446d99f3a368e3ba805812fc5bc09e52ef1c82f5a47e43b19973", size = 340172 }, + { url = "https://files.pythonhosted.org/packages/15/7f/4defee54893a3947936f3b5b8b1fe8cb10bb6d01cf87240345f511636e8d/py_sr25519_bindings-0.2.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0368dcdf5ec8d2bb9c13273c78c3c5b033211d37a70a2f1d2080f29a7d118340", size = 368044 }, + { url = "https://files.pythonhosted.org/packages/44/a9/b6ddb161bb28f7da1b261d8e6d59d9669a15bdbfe8bfff0ff15f9a28f0a6/py_sr25519_bindings-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2618b02b4a3babac07b8bb61fe9550f911f038bb079665682ca76b2e664e5258", size = 384053 }, + { url = "https://files.pythonhosted.org/packages/7a/66/5d4c78ad9766cd46e5439e9fb84cb10bc47b9c4929c8ea99ee880f405f50/py_sr25519_bindings-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ab1bc4dc524efefaecf3a85f4a0ff05c1ca9509d4d64056199984550f3c98b3", size = 365700 }, + { url = "https://files.pythonhosted.org/packages/07/ef/f96d4e2472af62768ffd81df2170f643de87b0ab831e405a4572b9959379/py_sr25519_bindings-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7ccdc89d5e3ae0dd163c8150ec76b6bb3291c1cec9746eb79e9544b3423f35f9", size = 385360 }, + { url = "https://files.pythonhosted.org/packages/9e/91/ea5e750e5f2896412fcbbe32da3be8ffab50f4221df7fe3ab367c51a99ac/py_sr25519_bindings-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ae6545c414cfa5d7207c9c77aaa576bb374982fb2105a7a9c2764afa5621f6d4", size = 523867 }, + { url = "https://files.pythonhosted.org/packages/7c/d0/e56f6753b264dd4c3f40364879429af7127c8b235c7a2f6d5fbb69137004/py_sr25519_bindings-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:7046774e39e0166d3c12632969c9d1713e6ad9ca8206bbe82923ba6935b0a01f", size = 627828 }, + { url = "https://files.pythonhosted.org/packages/63/19/7a8d5cca0a498da55b0457be98f03e428e4981b563e5d1c8c92dfc7d136e/py_sr25519_bindings-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cba9a8821176895b080ea761e5ab9cd8727660bf401478a6532a30ae3429573d", size = 551658 }, + { url = "https://files.pythonhosted.org/packages/58/4e/083694bded9ce2d8d598f086aa4ca67f2b9c5d9bfd79ca46f04c95e9322b/py_sr25519_bindings-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c31aba05819e5b6b26746dc1b078cf680bd471f135c55e376e95c7774e22e936", size = 529627 }, + { url = "https://files.pythonhosted.org/packages/3d/cc/837b57c938d2b1d0e6f296dc09a3e65b0d762b2387301f8a51452d679391/py_sr25519_bindings-0.2.1-cp311-none-win32.whl", hash = "sha256:d4bfb9c9a5c46563ccf12e74862ee95d2961556ba7aca62c9e4d6e4f7c37b4e0", size = 217894 }, + { url = "https://files.pythonhosted.org/packages/5e/43/3f91ccad4b8d96ddf9a26b00be11de6ad0d260ab26e17ad8f98088512c3a/py_sr25519_bindings-0.2.1-cp311-none-win_amd64.whl", hash = "sha256:4f0d5c065d5e6122e53e771035aa335534363b451358b408d211df1c46773617", size = 224191 }, + { url = "https://files.pythonhosted.org/packages/fa/6f/5dca831fe2617075237d49868d1bd4f025d0dbd23676d7dec3aaf39642cd/py_sr25519_bindings-0.2.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:01ef73c0b3d3f703b54ee69c0f5ff4aa54b4233212c466fd497c7a84d170963a", size = 330633 }, + { url = "https://files.pythonhosted.org/packages/3e/86/569b69e01a962e0c3cd63465e5faad589e54f0c27bfaed5436fef283d56c/py_sr25519_bindings-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7ce8ac85e5ea82825a863f3f6f071e5ead610d7675820eb8ffe772267445ec0b", size = 306030 }, + { url = "https://files.pythonhosted.org/packages/a1/ae/ad0d1fff92966b4ca020abc3ea12e3e1f34c3a937bab28fa0e6bf893d587/py_sr25519_bindings-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f59ac8c03c8ef819db063627f4a8247aab0db11d88b21562abbe371612cf66ab", size = 340266 }, + { url = "https://files.pythonhosted.org/packages/b0/7e/93903b1a0789fe1e7f2bb17f4992b55549dfbc8dd8dc3fa4d57c08b72250/py_sr25519_bindings-0.2.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d2c11fc77b57308e3ada9a40e7c343027129b582d3091ebd992c99b1832ac8c1", size = 367790 }, + { url = "https://files.pythonhosted.org/packages/f4/79/842a46cc48c33ff0d08f95db6b327fdd5972fd68d733634322762dd74702/py_sr25519_bindings-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92af2831d6896f0b3fef792d1f2da780fabf6c78dac12535b394cbdb51c0d257", size = 383790 }, + { url = "https://files.pythonhosted.org/packages/0d/33/aeeacf174483ae6163bfb8993c0dabdb15875272e59658123d2dcf55f39a/py_sr25519_bindings-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc99f7f310b7641e510810c1d6a6b51792ab2ccefac3ab288445a9fcbc9a8265", size = 365962 }, + { url = "https://files.pythonhosted.org/packages/85/bb/c41e0115115336acad5b05d577bf463fa69975ed84dcf50011ac4e07eb89/py_sr25519_bindings-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1dc4995a352a6e5851a41cb0ea37d8c9083d173515b7fd2f381b014f57dc1cda", size = 386028 }, + { url = "https://files.pythonhosted.org/packages/cd/d0/48744d7ec55853dc7ec6889f7b85b4f9d21349f09a9ccc8fd988a67f0a46/py_sr25519_bindings-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f103dc5c420057c4447bd6ebf28b2b68ff3ab8da85a5f7ff39c405293de80c78", size = 524320 }, + { url = "https://files.pythonhosted.org/packages/50/4f/9462c0525bd64417c56e788b9543a34c08583bf7eabf81797bf5545b924d/py_sr25519_bindings-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:902ee675497b8d356a2abe2abc4278cd76c503f76d06ef2bcd797c1df59e84b7", size = 628052 }, + { url = "https://files.pythonhosted.org/packages/a7/2a/873f8e7425fd424f9d4aa6eddbbe767889d2aee639372fd9516d6b352c93/py_sr25519_bindings-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5dd9748f4bd9a3bc4d5c1245f6edcc723075b1470b4c36add4474df4c53604e8", size = 552273 }, + { url = "https://files.pythonhosted.org/packages/0e/e2/bb29457851816c1637bdd7176ac419073faeecf452dcfae54b50ddb81bc1/py_sr25519_bindings-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c24bc55699d12948571969c26e65138a942bdaca062171288c40c44b9a4f266", size = 530013 }, + { url = "https://files.pythonhosted.org/packages/4b/70/21d32090ca207738a3979620865e2a48ccbed64871cffafb24c6febe234d/py_sr25519_bindings-0.2.1-cp312-none-win32.whl", hash = "sha256:d4799c9a8f280abdfe564d397bad45da380275c8d22604e059bd7b3d5af404b5", size = 218181 }, + { url = "https://files.pythonhosted.org/packages/bb/df/06a61ef52a6889d6879bfa8a5877688f62854c8eab491ad7af60e797a3ef/py_sr25519_bindings-0.2.1-cp312-none-win_amd64.whl", hash = "sha256:0746befd71d1766d8747910cfeb2cec2be2c859c3b3618eda1dc3cb4a1b85175", size = 224095 }, + { url = "https://files.pythonhosted.org/packages/f4/b8/e41ab03a4c0549beff4b839a13ec5e62be1314e6e7d3833da0ad78aac8ae/py_sr25519_bindings-0.2.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:89014247bb398acf99e508a0eff7b1dee8cea4b1d441ceeee8de275b1944812f", size = 331133 }, + { url = "https://files.pythonhosted.org/packages/e4/65/f19b357173288e0975324afd153d933d50766f0476b02c89085cf9485485/py_sr25519_bindings-0.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d3ce7c463b73864909391bfad078b1c88ebbc1eb84f58336c605cbcaf3cecd2f", size = 305935 }, + { url = "https://files.pythonhosted.org/packages/3d/2c/64f1f32347f70789b35488a4c46f4ab7327d55624c0c640bc36caf7e0a31/py_sr25519_bindings-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a2c28840138ba0a4e6f8c6953821cbd1d80d2e52404ff9722030a22d26addd", size = 340116 }, + { url = "https://files.pythonhosted.org/packages/46/f1/ad6f8348a2103a45dca7c74db5e83d8fd3e77156b265479c5cbf78aa4706/py_sr25519_bindings-0.2.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b0cea045676c3c482423232d19b6aac2458925416fcceec0a37c938f8bc9c00d", size = 367914 }, + { url = "https://files.pythonhosted.org/packages/bf/32/111948aadb68425d572be78caf8d0da15351b62f33cfd349a87c0c764147/py_sr25519_bindings-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cedbcc9779630c7cd364a66e686aa5c2ad0dd81fbb95edb689a6f63eb3323d6", size = 384008 }, + { url = "https://files.pythonhosted.org/packages/90/d6/b8e2972513392b881221e5047e7491d855616165e69ab69d9e708bbeb877/py_sr25519_bindings-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d064e6154554e18f3c40349c7df01297d812da5f6c4bcb825fa9f4fe2dd402d", size = 365633 }, + { url = "https://files.pythonhosted.org/packages/fc/b4/5875321cb868581a6e35697849fc21a9bb7a2a98ec43d895437088e73acc/py_sr25519_bindings-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6156c50f92b705d89f82b0dcb51eb0eaf0f22fba9fa51648a5e0c8274b0e0502", size = 385401 }, + { url = "https://files.pythonhosted.org/packages/10/f8/f37f52b8cd95be66cf38551d4fd075505da53e288d9ee002fa78582e9eca/py_sr25519_bindings-0.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a915deadf311592c9d7dc6cf6b0550830aeb08c5029cb06e882c32dcb560125b", size = 524079 }, + { url = "https://files.pythonhosted.org/packages/42/d3/2d8496aae39099ff4186ea42cdd64c69fd8c6eb6a4dd7b840b27ee1f8ab8/py_sr25519_bindings-0.2.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:8b56ceec5f83dd9c4b809f3be3ef4262d1e833d1ed8f16d7d8283fb2c5ae1a75", size = 627600 }, + { url = "https://files.pythonhosted.org/packages/a6/11/14587baa3654e632f64778bd0f6c01b8d8315ce3485bfca23464836bbe75/py_sr25519_bindings-0.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:73948c2b022287ff478a276b725a98a3bea34920cfe0edbedc0154f9a6125061", size = 551510 }, + { url = "https://files.pythonhosted.org/packages/3a/8c/6d4ba5e450ffdd8eba36fc2c841aad1615bec3c5356b38c7e2d8a3f67837/py_sr25519_bindings-0.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8bc937794b947b9da2f20fa0d8f5002d20d2bfc2656a21ef834e1af2d3fdca4", size = 529702 }, + { url = "https://files.pythonhosted.org/packages/6d/eb/28e34d708432e11ac149914c91e6db7532accd148571d9767e210b057c37/py_sr25519_bindings-0.2.1-cp39-none-win32.whl", hash = "sha256:d27b882546d5ad78f71c1ec48033267a0dd812fb1583881c39a75b3180a7e80b", size = 217899 }, + { url = "https://files.pythonhosted.org/packages/d5/cf/960acce8c2fb5209fe10d47a8116a6dd176e07cd7c369ff0a0864a0616b1/py_sr25519_bindings-0.2.1-cp39-none-win_amd64.whl", hash = "sha256:5ad0d7b14339452072773bae6d4570684895658a046279bebd3410941846ea65", size = 224202 }, + { url = "https://files.pythonhosted.org/packages/bf/21/d5a2b0d2b518fa530cd7b08d8906390c9b3eb2476b8d04f3b9eeae848207/py_sr25519_bindings-0.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50f8b34fed2c98814dcd414379ef43bf63cd4c05d7d90b83c590cca60fe804d6", size = 340467 }, + { url = "https://files.pythonhosted.org/packages/1e/92/38b9b6ae88eee7ffbe99fd0a577b82ff0ea2b030c92e85696355f1e1f0f4/py_sr25519_bindings-0.2.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:141b0f8fb99cb249984f7c9ec67dd1768aae4d137d47ea0eca027d669503e132", size = 368253 }, + { url = "https://files.pythonhosted.org/packages/d5/c5/90eb85986e929e4e004a5c1f4f1f158bf792426d7ace5a2d59ed3557dc8e/py_sr25519_bindings-0.2.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45cfef18bdfde67d445650a388bfafecbd1844a64c19087e9e4267548998c100", size = 384131 }, + { url = "https://files.pythonhosted.org/packages/31/04/a4575abaaf793836bd43f976288ab637edce45a0e523472d44681a3fe98c/py_sr25519_bindings-0.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:639410c0258a543bb84b0518616af724716737054ac5c78daa4d956d17841b17", size = 365591 }, + { url = "https://files.pythonhosted.org/packages/b8/fb/1d32c088d5c297c4c9f6d6887cec43a5f4bb677b058291555cd1ede6d870/py_sr25519_bindings-0.2.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a98e5a395445046f37fc4e365556ce06fa344e3b711de0564ac3fd2b351a1b3e", size = 385688 }, + { url = "https://files.pythonhosted.org/packages/9e/84/f2aa8a575d4dfc9d066dda65f571b814ac662cb81fbacaefd5244bb3df7b/py_sr25519_bindings-0.2.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:7935b79a91aa72db42b5015117018554980c320256e63bc930b8bd148a0765a4", size = 524790 }, + { url = "https://files.pythonhosted.org/packages/33/eb/5f2cba82b804cda52625570875aaea108b9a1c7c01b3ea8a33f34b656420/py_sr25519_bindings-0.2.1-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:cedf5d0669c23ddab8804982f665c7e99b13e8452db78128f231217b8528c31a", size = 628076 }, + { url = "https://files.pythonhosted.org/packages/c8/87/32b480bc5dfabf8e4ba43ced626d5ce40c0132fbb512ea22fbea63cf6447/py_sr25519_bindings-0.2.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:9ea24db07992f756409729adad1e3ec9aa0a9d4fece5da90768a56ac1563f0f4", size = 552147 }, + { url = "https://files.pythonhosted.org/packages/0b/7f/88d3a788c85727076f512fae958d464f49046cdd9a88958cf39b2b47ceb4/py_sr25519_bindings-0.2.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e8b7e42cd4a5177dd83bbcdef77591fd72d3da02616545011ebcdd872f8cc39d", size = 530561 }, + { url = "https://files.pythonhosted.org/packages/45/ed/aef8da74a5ce9858883edf0132a76b75535537fad49bdbdd2cee131eb0e9/py_sr25519_bindings-0.2.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:858b80041b18fdde666427ec9843303931ab2184cdf698285e8d34f3f6c4fad0", size = 340405 }, + { url = "https://files.pythonhosted.org/packages/6f/1c/60c20f5c331168ec4a5ced15abc54c448c99e1127d1c66b0e4fef08f0291/py_sr25519_bindings-0.2.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9a848030227b8099c26c4f38b35fbae55cb78e0d3fab69804bf220e60a85455", size = 368188 }, + { url = "https://files.pythonhosted.org/packages/1c/30/12faa4f7310924af691eb7c0658284915f367bdfba0b235a070078306d36/py_sr25519_bindings-0.2.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de7afdcc714fd83fc3636b9cea6c2ef6515e59f97410e73210276c3e0e64a28b", size = 384038 }, + { url = "https://files.pythonhosted.org/packages/84/90/35a2df0a13586318fb2018cf5e5176be9ec5b4d068cd14ab863eef08fba7/py_sr25519_bindings-0.2.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9333d891f1305f686f6ef4b9aef204df3090d037056e9f6e1276165c29ef70c2", size = 524698 }, + { url = "https://files.pythonhosted.org/packages/1d/09/3287b67ed0e460f8d46fc0ebb7950691573ea78305b380c8e2aa4d7a6d09/py_sr25519_bindings-0.2.1-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:970e0635104f2d5e771de3b8863eb0f7d04617c164d49d17e02ecc60c3a97182", size = 627969 }, + { url = "https://files.pythonhosted.org/packages/b9/5d/0cfd3ce5e8dc1b81927f64911ba0a9a2cbc8707fa93297efae00bf949797/py_sr25519_bindings-0.2.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:995e2c49dd0df3adb7907b2dc5a30d4df64160023205d89256b88a956c64637c", size = 552054 }, + { url = "https://files.pythonhosted.org/packages/c4/3f/1327696584ede04900a2590cf02a9e296b8afdb93b4fc0aa242a02df3d2b/py_sr25519_bindings-0.2.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4177bf68b73080ca0a21cf1231877dbec4f4485ee22bc97b7d447a0e29fe9c30", size = 530492 }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, +] + +[[package]] +name = "pycryptodome" +version = "3.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/52/13b9db4a913eee948152a079fe58d035bd3d1a519584155da8e786f767e6/pycryptodome-3.21.0.tar.gz", hash = "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297", size = 4818071 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/88/5e83de10450027c96c79dc65ac45e9d0d7a7fef334f39d3789a191f33602/pycryptodome-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4", size = 2495937 }, + { url = "https://files.pythonhosted.org/packages/66/e1/8f28cd8cf7f7563319819d1e172879ccce2333781ae38da61c28fe22d6ff/pycryptodome-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b", size = 1634629 }, + { url = "https://files.pythonhosted.org/packages/6a/c1/f75a1aaff0c20c11df8dc8e2bf8057e7f73296af7dfd8cbb40077d1c930d/pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e", size = 2168708 }, + { url = "https://files.pythonhosted.org/packages/ea/66/6f2b7ddb457b19f73b82053ecc83ba768680609d56dd457dbc7e902c41aa/pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8", size = 2254555 }, + { url = "https://files.pythonhosted.org/packages/2c/2b/152c330732a887a86cbf591ed69bd1b489439b5464806adb270f169ec139/pycryptodome-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1", size = 2294143 }, + { url = "https://files.pythonhosted.org/packages/55/92/517c5c498c2980c1b6d6b9965dffbe31f3cd7f20f40d00ec4069559c5902/pycryptodome-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a", size = 2160509 }, + { url = "https://files.pythonhosted.org/packages/39/1f/c74288f54d80a20a78da87df1818c6464ac1041d10988bb7d982c4153fbc/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2", size = 2329480 }, + { url = "https://files.pythonhosted.org/packages/39/1b/d0b013bf7d1af7cf0a6a4fce13f5fe5813ab225313755367b36e714a63f8/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93", size = 2254397 }, + { url = "https://files.pythonhosted.org/packages/14/71/4cbd3870d3e926c34706f705d6793159ac49d9a213e3ababcdade5864663/pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764", size = 1775641 }, + { url = "https://files.pythonhosted.org/packages/43/1d/81d59d228381576b92ecede5cd7239762c14001a828bdba30d64896e9778/pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53", size = 1812863 }, + { url = "https://files.pythonhosted.org/packages/25/b3/09ff7072e6d96c9939c24cf51d3c389d7c345bf675420355c22402f71b68/pycryptodome-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca", size = 1691593 }, + { url = "https://files.pythonhosted.org/packages/a8/91/38e43628148f68ba9b68dedbc323cf409e537fd11264031961fd7c744034/pycryptodome-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd", size = 1765997 }, + { url = "https://files.pythonhosted.org/packages/08/16/ae464d4ac338c1dd41f89c41f9488e54f7d2a3acf93bb920bb193b99f8e3/pycryptodome-3.21.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d5ebe0763c982f069d3877832254f64974139f4f9655058452603ff559c482e8", size = 1615855 }, + { url = "https://files.pythonhosted.org/packages/1e/8c/b0cee957eee1950ce7655006b26a8894cee1dc4b8747ae913684352786eb/pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee86cbde706be13f2dec5a42b52b1c1d1cbb90c8e405c68d0755134735c8dc6", size = 1650018 }, + { url = "https://files.pythonhosted.org/packages/93/4d/d7138068089b99f6b0368622e60f97a577c936d75f533552a82613060c58/pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fd54003ec3ce4e0f16c484a10bc5d8b9bd77fa662a12b85779a2d2d85d67ee0", size = 1687977 }, + { url = "https://files.pythonhosted.org/packages/96/02/90ae1ac9f28be4df0ed88c127bf4acc1b102b40053e172759d4d1c54d937/pycryptodome-3.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5dfafca172933506773482b0e18f0cd766fd3920bd03ec85a283df90d8a17bc6", size = 1788273 }, + { url = "https://files.pythonhosted.org/packages/04/cf/72831e972d2bd94f7ea8d8364b00f2bac2e848a601d6cff12376543152bb/pycryptodome-3.21.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:590ef0898a4b0a15485b05210b4a1c9de8806d3ad3d47f74ab1dc07c67a6827f", size = 1615737 }, + { url = "https://files.pythonhosted.org/packages/ce/b2/7b8b846ed3340cf266cc1fc57cc308fb4e569847f728e18d8e7c89954973/pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35e442630bc4bc2e1878482d6f59ea22e280d7121d7adeaedba58c23ab6386b", size = 1649932 }, + { url = "https://files.pythonhosted.org/packages/95/87/de5181de6e82aadd94ff6f1f6a58164b199f9bb953897682aa3bd0773c2f/pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff99f952db3db2fbe98a0b355175f93ec334ba3d01bbde25ad3a5a33abc02b58", size = 1687888 }, + { url = "https://files.pythonhosted.org/packages/33/c2/c7b6f7a9a7eb50f478804b933e64de5dcdc6726881d9004e0cb857a8b8ff/pycryptodome-3.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8acd7d34af70ee63f9a849f957558e49a98f8f1634f86a59d2be62bb8e93f71c", size = 1788556 }, +] + +[[package]] +name = "pygments" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/0b/32f05854cfd432e9286bb41a870e0d1a926b72df5f5cdb6dec962b2e369e/pymdown_extensions-10.12.tar.gz", hash = "sha256:b0ee1e0b2bef1071a47891ab17003bfe5bf824a398e13f49f8ed653b699369a7", size = 840790 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/32/95a164ddf533bd676cbbe878e36e89b4ade3efde8dd61d0148c90cbbe57e/pymdown_extensions-10.12-py3-none-any.whl", hash = "sha256:49f81412242d3527b8b4967b990df395c89563043bc51a3d2d7d500e52123b77", size = 263448 }, +] + +[[package]] +name = "pynacl" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/22/27582568be639dfe22ddb3902225f91f2f17ceff88ce80e4db396c8986da/PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba", size = 3392854 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/75/0b8ede18506041c0bf23ac4d8e2971b4161cd6ce630b177d0a08eb0d8857/PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1", size = 349920 }, + { url = "https://files.pythonhosted.org/packages/59/bb/fddf10acd09637327a97ef89d2a9d621328850a72f1fdc8c08bdf72e385f/PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92", size = 601722 }, + { url = "https://files.pythonhosted.org/packages/5d/70/87a065c37cca41a75f2ce113a5a2c2aa7533be648b184ade58971b5f7ccc/PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394", size = 680087 }, + { url = "https://files.pythonhosted.org/packages/ee/87/f1bb6a595f14a327e8285b9eb54d41fef76c585a0edef0a45f6fc95de125/PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d", size = 856678 }, + { url = "https://files.pythonhosted.org/packages/66/28/ca86676b69bf9f90e710571b67450508484388bfce09acf8a46f0b8c785f/PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858", size = 1133660 }, + { url = "https://files.pythonhosted.org/packages/3d/85/c262db650e86812585e2bc59e497a8f59948a005325a11bbbc9ecd3fe26b/PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b", size = 663824 }, + { url = "https://files.pythonhosted.org/packages/fd/1a/cc308a884bd299b651f1633acb978e8596c71c33ca85e9dc9fa33a5399b9/PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff", size = 1117912 }, + { url = "https://files.pythonhosted.org/packages/25/2d/b7df6ddb0c2a33afdb358f8af6ea3b8c4d1196ca45497dd37a56f0c122be/PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543", size = 204624 }, + { url = "https://files.pythonhosted.org/packages/5e/22/d3db169895faaf3e2eda892f005f433a62db2decbcfbc2f61e6517adfa87/PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93", size = 212141 }, +] + +[[package]] +name = "pytest" +version = "8.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, +] + +[[package]] +name = "pytest-asyncio" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 }, +] + +[[package]] +name = "pytest-cov" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 }, +] + +[[package]] +name = "pytest-cover" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest-cov" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/27/20964101a7cdb260f8d6c4e854659026968321d10c90552b1fe7f6c5f913/pytest-cover-3.0.0.tar.gz", hash = "sha256:5bdb6c1cc3dd75583bb7bc2c57f5e1034a1bfcb79d27c71aceb0b16af981dbf4", size = 3211 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/9b/7b4700c462628e169bd859c6368d596a6aedc87936bde733bead9f875fce/pytest_cover-3.0.0-py2.py3-none-any.whl", hash = "sha256:578249955eb3b5f3991209df6e532bb770b647743b7392d3d97698dc02f39ebb", size = 3769 }, +] + +[[package]] +name = "pytest-coverage" +version = "0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest-cover" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/81/1d954849aed17b254d1c397eb4447a05eedce612a56b627c071df2ce00c1/pytest-coverage-0.0.tar.gz", hash = "sha256:db6af2cbd7e458c7c9fd2b4207cee75258243c8a81cad31a7ee8cfad5be93c05", size = 873 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/4b/d95b052f87db89a2383233c0754c45f6d3b427b7a4bcb771ac9316a6fae1/pytest_coverage-0.0-py2.py3-none-any.whl", hash = "sha256:dedd084c5e74d8e669355325916dc011539b190355021b037242514dee546368", size = 2013 }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199 }, + { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758 }, + { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463 }, + { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280 }, + { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239 }, + { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802 }, + { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527 }, + { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052 }, + { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774 }, + { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, + { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, + { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, + { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, + { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, + { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, + { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, + { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, + { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, + { url = "https://files.pythonhosted.org/packages/65/d8/b7a1db13636d7fb7d4ff431593c510c8b8fca920ade06ca8ef20015493c5/PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", size = 184777 }, + { url = "https://files.pythonhosted.org/packages/0a/02/6ec546cd45143fdf9840b2c6be8d875116a64076218b61d68e12548e5839/PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", size = 172318 }, + { url = "https://files.pythonhosted.org/packages/0e/9a/8cc68be846c972bda34f6c2a93abb644fb2476f4dcc924d52175786932c9/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", size = 720891 }, + { url = "https://files.pythonhosted.org/packages/e9/6c/6e1b7f40181bc4805e2e07f4abc10a88ce4648e7e95ff1abe4ae4014a9b2/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", size = 722614 }, + { url = "https://files.pythonhosted.org/packages/3d/32/e7bd8535d22ea2874cef6a81021ba019474ace0d13a4819c2a4bce79bd6a/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", size = 737360 }, + { url = "https://files.pythonhosted.org/packages/d7/12/7322c1e30b9be969670b672573d45479edef72c9a0deac3bb2868f5d7469/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", size = 699006 }, + { url = "https://files.pythonhosted.org/packages/82/72/04fcad41ca56491995076630c3ec1e834be241664c0c09a64c9a2589b507/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", size = 723577 }, + { url = "https://files.pythonhosted.org/packages/ed/5e/46168b1f2757f1fcd442bc3029cd8767d88a98c9c05770d8b420948743bb/PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", size = 144593 }, + { url = "https://files.pythonhosted.org/packages/19/87/5124b1c1f2412bb95c59ec481eaf936cd32f0fe2a7b16b97b81c4c017a6a/PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", size = 162312 }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/8e/da1c6c58f751b70f8ceb1eb25bc25d524e8f14fe16edcce3f4e3ba08629c/pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", size = 5631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/66/bbb1dd374f5c870f59c5bb1db0e18cbe7fa739415a24cbd95b2d1f5ae0c4/pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069", size = 3911 }, +] + +[[package]] +name = "regex" +version = "2024.11.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674 }, + { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684 }, + { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589 }, + { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511 }, + { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149 }, + { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707 }, + { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702 }, + { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976 }, + { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397 }, + { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726 }, + { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098 }, + { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325 }, + { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277 }, + { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197 }, + { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714 }, + { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042 }, + { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669 }, + { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684 }, + { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589 }, + { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121 }, + { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275 }, + { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257 }, + { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727 }, + { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667 }, + { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963 }, + { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700 }, + { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592 }, + { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929 }, + { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213 }, + { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734 }, + { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052 }, + { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781 }, + { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455 }, + { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759 }, + { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976 }, + { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077 }, + { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160 }, + { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896 }, + { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997 }, + { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725 }, + { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481 }, + { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896 }, + { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138 }, + { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692 }, + { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135 }, + { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567 }, + { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525 }, + { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324 }, + { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617 }, + { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023 }, + { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072 }, + { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130 }, + { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857 }, + { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006 }, + { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650 }, + { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545 }, + { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045 }, + { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182 }, + { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733 }, + { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122 }, + { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545 }, + { url = "https://files.pythonhosted.org/packages/89/23/c4a86df398e57e26f93b13ae63acce58771e04bdde86092502496fa57f9c/regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839", size = 482682 }, + { url = "https://files.pythonhosted.org/packages/3c/8b/45c24ab7a51a1658441b961b86209c43e6bb9d39caf1e63f46ce6ea03bc7/regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e", size = 287679 }, + { url = "https://files.pythonhosted.org/packages/7a/d1/598de10b17fdafc452d11f7dada11c3be4e379a8671393e4e3da3c4070df/regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf", size = 284578 }, + { url = "https://files.pythonhosted.org/packages/49/70/c7eaa219efa67a215846766fde18d92d54cb590b6a04ffe43cef30057622/regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b", size = 782012 }, + { url = "https://files.pythonhosted.org/packages/89/e5/ef52c7eb117dd20ff1697968219971d052138965a4d3d9b95e92e549f505/regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0", size = 820580 }, + { url = "https://files.pythonhosted.org/packages/5f/3f/9f5da81aff1d4167ac52711acf789df13e789fe6ac9545552e49138e3282/regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b", size = 809110 }, + { url = "https://files.pythonhosted.org/packages/86/44/2101cc0890c3621b90365c9ee8d7291a597c0722ad66eccd6ffa7f1bcc09/regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef", size = 780919 }, + { url = "https://files.pythonhosted.org/packages/ce/2e/3e0668d8d1c7c3c0d397bf54d92fc182575b3a26939aed5000d3cc78760f/regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48", size = 771515 }, + { url = "https://files.pythonhosted.org/packages/a6/49/1bc4584254355e3dba930a3a2fd7ad26ccba3ebbab7d9100db0aff2eedb0/regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13", size = 696957 }, + { url = "https://files.pythonhosted.org/packages/c8/dd/42879c1fc8a37a887cd08e358af3d3ba9e23038cd77c7fe044a86d9450ba/regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2", size = 768088 }, + { url = "https://files.pythonhosted.org/packages/89/96/c05a0fe173cd2acd29d5e13c1adad8b706bcaa71b169e1ee57dcf2e74584/regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95", size = 774752 }, + { url = "https://files.pythonhosted.org/packages/b5/f3/a757748066255f97f14506483436c5f6aded7af9e37bca04ec30c90ca683/regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9", size = 838862 }, + { url = "https://files.pythonhosted.org/packages/5c/93/c6d2092fd479dcaeea40fc8fa673822829181ded77d294a7f950f1dda6e2/regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f", size = 842622 }, + { url = "https://files.pythonhosted.org/packages/ff/9c/daa99532c72f25051a90ef90e1413a8d54413a9e64614d9095b0c1c154d0/regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b", size = 772713 }, + { url = "https://files.pythonhosted.org/packages/13/5d/61a533ccb8c231b474ac8e3a7d70155b00dfc61af6cafdccd1947df6d735/regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57", size = 261756 }, + { url = "https://files.pythonhosted.org/packages/dc/7b/e59b7f7c91ae110d154370c24133f947262525b5d6406df65f23422acc17/regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983", size = 274110 }, +] + +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, +] + +[[package]] +name = "ruff" +version = "0.7.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/8b/bc4e0dfa1245b07cf14300e10319b98e958a53ff074c1dd86b35253a8c2a/ruff-0.7.4.tar.gz", hash = "sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2", size = 3275547 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/4b/f5094719e254829766b807dadb766841124daba75a37da83e292ae5ad12f/ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478", size = 10447512 }, + { url = "https://files.pythonhosted.org/packages/9e/1d/3d2d2c9f601cf6044799c5349ff5267467224cefed9b35edf5f1f36486e9/ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63", size = 10235436 }, + { url = "https://files.pythonhosted.org/packages/62/83/42a6ec6216ded30b354b13e0e9327ef75a3c147751aaf10443756cb690e9/ruff-0.7.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20", size = 9888936 }, + { url = "https://files.pythonhosted.org/packages/4d/26/e1e54893b13046a6ad05ee9b89ee6f71542ba250f72b4c7a7d17c3dbf73d/ruff-0.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109", size = 10697353 }, + { url = "https://files.pythonhosted.org/packages/21/24/98d2e109c4efc02bfef144ec6ea2c3e1217e7ce0cfddda8361d268dfd499/ruff-0.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452", size = 10228078 }, + { url = "https://files.pythonhosted.org/packages/ad/b7/964c75be9bc2945fc3172241b371197bb6d948cc69e28bc4518448c368f3/ruff-0.7.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea", size = 11264823 }, + { url = "https://files.pythonhosted.org/packages/12/8d/20abdbf705969914ce40988fe71a554a918deaab62c38ec07483e77866f6/ruff-0.7.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7", size = 11951855 }, + { url = "https://files.pythonhosted.org/packages/b8/fc/6519ce58c57b4edafcdf40920b7273dfbba64fc6ebcaae7b88e4dc1bf0a8/ruff-0.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05", size = 11516580 }, + { url = "https://files.pythonhosted.org/packages/37/1a/5ec1844e993e376a86eb2456496831ed91b4398c434d8244f89094758940/ruff-0.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06", size = 12692057 }, + { url = "https://files.pythonhosted.org/packages/50/90/76867152b0d3c05df29a74bb028413e90f704f0f6701c4801174ba47f959/ruff-0.7.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc", size = 11085137 }, + { url = "https://files.pythonhosted.org/packages/c8/eb/0a7cb6059ac3555243bd026bb21785bbc812f7bbfa95a36c101bd72b47ae/ruff-0.7.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172", size = 10681243 }, + { url = "https://files.pythonhosted.org/packages/5e/76/2270719dbee0fd35780b05c08a07b7a726c3da9f67d9ae89ef21fc18e2e5/ruff-0.7.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a", size = 10319187 }, + { url = "https://files.pythonhosted.org/packages/9f/e5/39100f72f8ba70bec1bd329efc880dea8b6c1765ea1cb9d0c1c5f18b8d7f/ruff-0.7.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd", size = 10803715 }, + { url = "https://files.pythonhosted.org/packages/a5/89/40e904784f305fb56850063f70a998a64ebba68796d823dde67e89a24691/ruff-0.7.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a", size = 11162912 }, + { url = "https://files.pythonhosted.org/packages/8d/1b/dd77503b3875c51e3dbc053fd8367b845ab8b01c9ca6d0c237082732856c/ruff-0.7.4-py3-none-win32.whl", hash = "sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac", size = 8702767 }, + { url = "https://files.pythonhosted.org/packages/63/76/253ddc3e89e70165bba952ecca424b980b8d3c2598ceb4fc47904f424953/ruff-0.7.4-py3-none-win_amd64.whl", hash = "sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6", size = 9497534 }, + { url = "https://files.pythonhosted.org/packages/aa/70/f8724f31abc0b329ca98b33d73c14020168babcf71b0cba3cded5d9d0e66/ruff-0.7.4-py3-none-win_arm64.whl", hash = "sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f", size = 8851590 }, +] + +[[package]] +name = "scalecodec" +version = "1.2.11" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "base58" }, + { name = "more-itertools" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/7c/703893e7a8751318517a3dd8c0c060b2c30ffa33f4ab5dd6a4ed483f7967/scalecodec-1.2.11.tar.gz", hash = "sha256:99a2cdbfccdcaf22bd86b86da55a730a2855514ad2309faef4a4a93ac6cbeb8d", size = 150260 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/60/2a903fa9ed3dfc842240da22969a25b16ea213ed3ee25b7ba8ae1cba20c7/scalecodec-1.2.11-py3-none-any.whl", hash = "sha256:d15c94965f617caa25096f83a45f5f73031d05e6ee08d6039969f0a64fc35de1", size = 99164 }, +] + +[[package]] +name = "six" +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 }, +] + +[[package]] +name = "substrate-interface-async" +version = "1.7.10" +source = { virtual = "." } +dependencies = [ + { name = "aiohttp" }, + { name = "orjson" }, + { name = "scalecodec" }, + { name = "websocket-client" }, + { name = "xxhash" }, +] + +[package.optional-dependencies] +full = [ + { name = "base58" }, + { name = "certifi" }, + { name = "ecdsa" }, + { name = "eth-keys" }, + { name = "eth-utils" }, + { name = "idna" }, + { name = "py-bip39-bindings" }, + { name = "py-ed25519-zebra-bindings" }, + { name = "py-sr25519-bindings" }, + { name = "pycryptodome" }, + { name = "pynacl" }, +] + +[package.dev-dependencies] +dev = [ + { name = "black" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocs-material" }, + { name = "mkdocstrings", extra = ["python"] }, + { name = "mypy" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-coverage" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "aiohttp", specifier = ">=3.11.6" }, + { name = "base58", marker = "extra == 'full'", specifier = ">=2.1.1" }, + { name = "certifi", marker = "extra == 'full'", specifier = ">=2024.8.30" }, + { name = "ecdsa", marker = "extra == 'full'", specifier = ">=0.19.0" }, + { name = "eth-keys", marker = "extra == 'full'", specifier = ">=0.6.0" }, + { name = "eth-utils", marker = "extra == 'full'", specifier = ">=5.1.0" }, + { name = "idna", marker = "extra == 'full'", specifier = ">=3.10" }, + { name = "orjson", specifier = ">=3.10.12" }, + { name = "py-bip39-bindings", marker = "extra == 'full'", specifier = ">=0.1.12" }, + { name = "py-ed25519-zebra-bindings", marker = "extra == 'full'", specifier = ">=1.1.0" }, + { name = "py-sr25519-bindings", marker = "extra == 'full'", specifier = ">=0.2.1" }, + { name = "pycryptodome", marker = "extra == 'full'", specifier = ">=3.21.0" }, + { name = "pynacl", marker = "extra == 'full'", specifier = ">=1.5.0" }, + { name = "scalecodec", specifier = ">=1.2.11" }, + { name = "websocket-client", specifier = ">=1.8.0" }, + { name = "xxhash", specifier = ">=3.5.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "black", specifier = ">=24.10.0" }, + { name = "mkdocs", specifier = ">=1.6.1" }, + { name = "mkdocs-autorefs", specifier = ">=1.2.0" }, + { name = "mkdocs-material", specifier = ">=9.5.45" }, + { name = "mkdocstrings", extras = ["python"], specifier = ">=0.27.0" }, + { name = "mypy", specifier = ">=1.13.0" }, + { name = "pytest", specifier = ">=8.3.3" }, + { name = "pytest-asyncio", specifier = ">=0.24.0" }, + { name = "pytest-coverage", specifier = ">=0.0" }, + { name = "ruff", specifier = ">=0.7.4" }, +] + +[[package]] +name = "tomli" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/e4/1b6cbcc82d8832dd0ce34767d5c560df8a3547ad8cbc427f34601415930a/tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8", size = 16622 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/f7/4da0ffe1892122c9ea096c57f64c2753ae5dd3ce85488802d11b0992cc6d/tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391", size = 13750 }, +] + +[[package]] +name = "toolz" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383 }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390 }, + { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389 }, + { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020 }, + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393 }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392 }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019 }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471 }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449 }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054 }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480 }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451 }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057 }, + { url = "https://files.pythonhosted.org/packages/05/52/7223011bb760fce8ddc53416beb65b83a3ea6d7d13738dde75eeb2c89679/watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", size = 96390 }, + { url = "https://files.pythonhosted.org/packages/9c/62/d2b21bc4e706d3a9d467561f487c2938cbd881c69f3808c43ac1ec242391/watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", size = 88386 }, + { url = "https://files.pythonhosted.org/packages/ea/22/1c90b20eda9f4132e4603a26296108728a8bfe9584b006bd05dd94548853/watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", size = 89017 }, + { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902 }, + { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380 }, + { url = "https://files.pythonhosted.org/packages/5b/79/69f2b0e8d3f2afd462029031baafb1b75d11bb62703f0e1022b2e54d49ee/watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", size = 87903 }, + { url = "https://files.pythonhosted.org/packages/e2/2b/dc048dd71c2e5f0f7ebc04dd7912981ec45793a03c0dc462438e0591ba5d/watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", size = 88381 }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, +] + +[[package]] +name = "websocket-client" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826 }, +] + +[[package]] +name = "xxhash" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/5e/d6e5258d69df8b4ed8c83b6664f2b47d30d2dec551a29ad72a6c69eafd31/xxhash-3.5.0.tar.gz", hash = "sha256:84f2caddf951c9cbf8dc2e22a89d4ccf5d86391ac6418fe81e3c67d0cf60b45f", size = 84241 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/8a/0e9feca390d512d293afd844d31670e25608c4a901e10202aa98785eab09/xxhash-3.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ece616532c499ee9afbb83078b1b952beffef121d989841f7f4b3dc5ac0fd212", size = 31970 }, + { url = "https://files.pythonhosted.org/packages/16/e6/be5aa49580cd064a18200ab78e29b88b1127e1a8c7955eb8ecf81f2626eb/xxhash-3.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3171f693dbc2cef6477054a665dc255d996646b4023fe56cb4db80e26f4cc520", size = 30801 }, + { url = "https://files.pythonhosted.org/packages/20/ee/b8a99ebbc6d1113b3a3f09e747fa318c3cde5b04bd9c197688fadf0eeae8/xxhash-3.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c5d3e570ef46adaf93fc81b44aca6002b5a4d8ca11bd0580c07eac537f36680", size = 220927 }, + { url = "https://files.pythonhosted.org/packages/58/62/15d10582ef159283a5c2b47f6d799fc3303fe3911d5bb0bcc820e1ef7ff4/xxhash-3.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cb29a034301e2982df8b1fe6328a84f4b676106a13e9135a0d7e0c3e9f806da", size = 200360 }, + { url = "https://files.pythonhosted.org/packages/23/41/61202663ea9b1bd8e53673b8ec9e2619989353dba8cfb68e59a9cbd9ffe3/xxhash-3.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0d307d27099bb0cbeea7260eb39ed4fdb99c5542e21e94bb6fd29e49c57a23", size = 428528 }, + { url = "https://files.pythonhosted.org/packages/f2/07/d9a3059f702dec5b3b703737afb6dda32f304f6e9da181a229dafd052c29/xxhash-3.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0342aafd421795d740e514bc9858ebddfc705a75a8c5046ac56d85fe97bf196", size = 194149 }, + { url = "https://files.pythonhosted.org/packages/eb/58/27caadf78226ecf1d62dbd0c01d152ed381c14c1ee4ad01f0d460fc40eac/xxhash-3.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dbbd9892c5ebffeca1ed620cf0ade13eb55a0d8c84e0751a6653adc6ac40d0c", size = 207703 }, + { url = "https://files.pythonhosted.org/packages/b1/08/32d558ce23e1e068453c39aed7b3c1cdc690c177873ec0ca3a90d5808765/xxhash-3.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4cc2d67fdb4d057730c75a64c5923abfa17775ae234a71b0200346bfb0a7f482", size = 216255 }, + { url = "https://files.pythonhosted.org/packages/3f/d4/2b971e2d2b0a61045f842b622ef11e94096cf1f12cd448b6fd426e80e0e2/xxhash-3.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ec28adb204b759306a3d64358a5e5c07d7b1dd0ccbce04aa76cb9377b7b70296", size = 202744 }, + { url = "https://files.pythonhosted.org/packages/19/ae/6a6438864a8c4c39915d7b65effd85392ebe22710412902487e51769146d/xxhash-3.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1328f6d8cca2b86acb14104e381225a3d7b42c92c4b86ceae814e5c400dbb415", size = 210115 }, + { url = "https://files.pythonhosted.org/packages/48/7d/b3c27c27d1fc868094d02fe4498ccce8cec9fcc591825c01d6bcb0b4fc49/xxhash-3.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8d47ebd9f5d9607fd039c1fbf4994e3b071ea23eff42f4ecef246ab2b7334198", size = 414247 }, + { url = "https://files.pythonhosted.org/packages/a1/05/918f9e7d2fbbd334b829997045d341d6239b563c44e683b9a7ef8fe50f5d/xxhash-3.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b96d559e0fcddd3343c510a0fe2b127fbff16bf346dd76280b82292567523442", size = 191419 }, + { url = "https://files.pythonhosted.org/packages/08/29/dfe393805b2f86bfc47c290b275f0b7c189dc2f4e136fd4754f32eb18a8d/xxhash-3.5.0-cp310-cp310-win32.whl", hash = "sha256:61c722ed8d49ac9bc26c7071eeaa1f6ff24053d553146d5df031802deffd03da", size = 30114 }, + { url = "https://files.pythonhosted.org/packages/7b/d7/aa0b22c4ebb7c3ccb993d4c565132abc641cd11164f8952d89eb6a501909/xxhash-3.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:9bed5144c6923cc902cd14bb8963f2d5e034def4486ab0bbe1f58f03f042f9a9", size = 30003 }, + { url = "https://files.pythonhosted.org/packages/69/12/f969b81541ee91b55f1ce469d7ab55079593c80d04fd01691b550e535000/xxhash-3.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:893074d651cf25c1cc14e3bea4fceefd67f2921b1bb8e40fcfeba56820de80c6", size = 26773 }, + { url = "https://files.pythonhosted.org/packages/b8/c7/afed0f131fbda960ff15eee7f304fa0eeb2d58770fade99897984852ef23/xxhash-3.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02c2e816896dc6f85922ced60097bcf6f008dedfc5073dcba32f9c8dd786f3c1", size = 31969 }, + { url = "https://files.pythonhosted.org/packages/8c/0c/7c3bc6d87e5235672fcc2fb42fd5ad79fe1033925f71bf549ee068c7d1ca/xxhash-3.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6027dcd885e21581e46d3c7f682cfb2b870942feeed58a21c29583512c3f09f8", size = 30800 }, + { url = "https://files.pythonhosted.org/packages/04/9e/01067981d98069eec1c20201f8c145367698e9056f8bc295346e4ea32dd1/xxhash-3.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1308fa542bbdbf2fa85e9e66b1077eea3a88bef38ee8a06270b4298a7a62a166", size = 221566 }, + { url = "https://files.pythonhosted.org/packages/d4/09/d4996de4059c3ce5342b6e1e6a77c9d6c91acce31f6ed979891872dd162b/xxhash-3.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c28b2fdcee797e1c1961cd3bcd3d545cab22ad202c846235197935e1df2f8ef7", size = 201214 }, + { url = "https://files.pythonhosted.org/packages/62/f5/6d2dc9f8d55a7ce0f5e7bfef916e67536f01b85d32a9fbf137d4cadbee38/xxhash-3.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:924361811732ddad75ff23e90efd9ccfda4f664132feecb90895bade6a1b4623", size = 429433 }, + { url = "https://files.pythonhosted.org/packages/d9/72/9256303f10e41ab004799a4aa74b80b3c5977d6383ae4550548b24bd1971/xxhash-3.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89997aa1c4b6a5b1e5b588979d1da048a3c6f15e55c11d117a56b75c84531f5a", size = 194822 }, + { url = "https://files.pythonhosted.org/packages/34/92/1a3a29acd08248a34b0e6a94f4e0ed9b8379a4ff471f1668e4dce7bdbaa8/xxhash-3.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:685c4f4e8c59837de103344eb1c8a3851f670309eb5c361f746805c5471b8c88", size = 208538 }, + { url = "https://files.pythonhosted.org/packages/53/ad/7fa1a109663366de42f724a1cdb8e796a260dbac45047bce153bc1e18abf/xxhash-3.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbd2ecfbfee70bc1a4acb7461fa6af7748ec2ab08ac0fa298f281c51518f982c", size = 216953 }, + { url = "https://files.pythonhosted.org/packages/35/02/137300e24203bf2b2a49b48ce898ecce6fd01789c0fcd9c686c0a002d129/xxhash-3.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:25b5a51dc3dfb20a10833c8eee25903fd2e14059e9afcd329c9da20609a307b2", size = 203594 }, + { url = "https://files.pythonhosted.org/packages/23/03/aeceb273933d7eee248c4322b98b8e971f06cc3880e5f7602c94e5578af5/xxhash-3.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a8fb786fb754ef6ff8c120cb96629fb518f8eb5a61a16aac3a979a9dbd40a084", size = 210971 }, + { url = "https://files.pythonhosted.org/packages/e3/64/ed82ec09489474cbb35c716b189ddc1521d8b3de12b1b5ab41ce7f70253c/xxhash-3.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a905ad00ad1e1c34fe4e9d7c1d949ab09c6fa90c919860c1534ff479f40fd12d", size = 415050 }, + { url = "https://files.pythonhosted.org/packages/71/43/6db4c02dcb488ad4e03bc86d70506c3d40a384ee73c9b5c93338eb1f3c23/xxhash-3.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:963be41bcd49f53af6d795f65c0da9b4cc518c0dd9c47145c98f61cb464f4839", size = 192216 }, + { url = "https://files.pythonhosted.org/packages/22/6d/db4abec29e7a567455344433d095fdb39c97db6955bb4a2c432e486b4d28/xxhash-3.5.0-cp311-cp311-win32.whl", hash = "sha256:109b436096d0a2dd039c355fa3414160ec4d843dfecc64a14077332a00aeb7da", size = 30120 }, + { url = "https://files.pythonhosted.org/packages/52/1c/fa3b61c0cf03e1da4767213672efe186b1dfa4fc901a4a694fb184a513d1/xxhash-3.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:b702f806693201ad6c0a05ddbbe4c8f359626d0b3305f766077d51388a6bac58", size = 30003 }, + { url = "https://files.pythonhosted.org/packages/6b/8e/9e6fc572acf6e1cc7ccb01973c213f895cb8668a9d4c2b58a99350da14b7/xxhash-3.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:c4dcb4120d0cc3cc448624147dba64e9021b278c63e34a38789b688fd0da9bf3", size = 26777 }, + { url = "https://files.pythonhosted.org/packages/07/0e/1bfce2502c57d7e2e787600b31c83535af83746885aa1a5f153d8c8059d6/xxhash-3.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:14470ace8bd3b5d51318782cd94e6f94431974f16cb3b8dc15d52f3b69df8e00", size = 31969 }, + { url = "https://files.pythonhosted.org/packages/3f/d6/8ca450d6fe5b71ce521b4e5db69622383d039e2b253e9b2f24f93265b52c/xxhash-3.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59aa1203de1cb96dbeab595ded0ad0c0056bb2245ae11fac11c0ceea861382b9", size = 30787 }, + { url = "https://files.pythonhosted.org/packages/5b/84/de7c89bc6ef63d750159086a6ada6416cc4349eab23f76ab870407178b93/xxhash-3.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08424f6648526076e28fae6ea2806c0a7d504b9ef05ae61d196d571e5c879c84", size = 220959 }, + { url = "https://files.pythonhosted.org/packages/fe/86/51258d3e8a8545ff26468c977101964c14d56a8a37f5835bc0082426c672/xxhash-3.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61a1ff00674879725b194695e17f23d3248998b843eb5e933007ca743310f793", size = 200006 }, + { url = "https://files.pythonhosted.org/packages/02/0a/96973bd325412feccf23cf3680fd2246aebf4b789122f938d5557c54a6b2/xxhash-3.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2f2c61bee5844d41c3eb015ac652a0229e901074951ae48581d58bfb2ba01be", size = 428326 }, + { url = "https://files.pythonhosted.org/packages/11/a7/81dba5010f7e733de88af9555725146fc133be97ce36533867f4c7e75066/xxhash-3.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d32a592cac88d18cc09a89172e1c32d7f2a6e516c3dfde1b9adb90ab5df54a6", size = 194380 }, + { url = "https://files.pythonhosted.org/packages/fb/7d/f29006ab398a173f4501c0e4977ba288f1c621d878ec217b4ff516810c04/xxhash-3.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70dabf941dede727cca579e8c205e61121afc9b28516752fd65724be1355cc90", size = 207934 }, + { url = "https://files.pythonhosted.org/packages/8a/6e/6e88b8f24612510e73d4d70d9b0c7dff62a2e78451b9f0d042a5462c8d03/xxhash-3.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e5d0ddaca65ecca9c10dcf01730165fd858533d0be84c75c327487c37a906a27", size = 216301 }, + { url = "https://files.pythonhosted.org/packages/af/51/7862f4fa4b75a25c3b4163c8a873f070532fe5f2d3f9b3fc869c8337a398/xxhash-3.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e5b5e16c5a480fe5f59f56c30abdeba09ffd75da8d13f6b9b6fd224d0b4d0a2", size = 203351 }, + { url = "https://files.pythonhosted.org/packages/22/61/8d6a40f288f791cf79ed5bb113159abf0c81d6efb86e734334f698eb4c59/xxhash-3.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149b7914451eb154b3dfaa721315117ea1dac2cc55a01bfbd4df7c68c5dd683d", size = 210294 }, + { url = "https://files.pythonhosted.org/packages/17/02/215c4698955762d45a8158117190261b2dbefe9ae7e5b906768c09d8bc74/xxhash-3.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:eade977f5c96c677035ff39c56ac74d851b1cca7d607ab3d8f23c6b859379cab", size = 414674 }, + { url = "https://files.pythonhosted.org/packages/31/5c/b7a8db8a3237cff3d535261325d95de509f6a8ae439a5a7a4ffcff478189/xxhash-3.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa9f547bd98f5553d03160967866a71056a60960be00356a15ecc44efb40ba8e", size = 192022 }, + { url = "https://files.pythonhosted.org/packages/78/e3/dd76659b2811b3fd06892a8beb850e1996b63e9235af5a86ea348f053e9e/xxhash-3.5.0-cp312-cp312-win32.whl", hash = "sha256:f7b58d1fd3551b8c80a971199543379be1cee3d0d409e1f6d8b01c1a2eebf1f8", size = 30170 }, + { url = "https://files.pythonhosted.org/packages/d9/6b/1c443fe6cfeb4ad1dcf231cdec96eb94fb43d6498b4469ed8b51f8b59a37/xxhash-3.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:fa0cafd3a2af231b4e113fba24a65d7922af91aeb23774a8b78228e6cd785e3e", size = 30040 }, + { url = "https://files.pythonhosted.org/packages/0f/eb/04405305f290173acc0350eba6d2f1a794b57925df0398861a20fbafa415/xxhash-3.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:586886c7e89cb9828bcd8a5686b12e161368e0064d040e225e72607b43858ba2", size = 26796 }, + { url = "https://files.pythonhosted.org/packages/c9/b8/e4b3ad92d249be5c83fa72916c9091b0965cb0faeff05d9a0a3870ae6bff/xxhash-3.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:37889a0d13b0b7d739cfc128b1c902f04e32de17b33d74b637ad42f1c55101f6", size = 31795 }, + { url = "https://files.pythonhosted.org/packages/fc/d8/b3627a0aebfbfa4c12a41e22af3742cf08c8ea84f5cc3367b5de2d039cce/xxhash-3.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:97a662338797c660178e682f3bc180277b9569a59abfb5925e8620fba00b9fc5", size = 30792 }, + { url = "https://files.pythonhosted.org/packages/c3/cc/762312960691da989c7cd0545cb120ba2a4148741c6ba458aa723c00a3f8/xxhash-3.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f85e0108d51092bdda90672476c7d909c04ada6923c14ff9d913c4f7dc8a3bc", size = 220950 }, + { url = "https://files.pythonhosted.org/packages/fe/e9/cc266f1042c3c13750e86a535496b58beb12bf8c50a915c336136f6168dc/xxhash-3.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2fd827b0ba763ac919440042302315c564fdb797294d86e8cdd4578e3bc7f3", size = 199980 }, + { url = "https://files.pythonhosted.org/packages/bf/85/a836cd0dc5cc20376de26b346858d0ac9656f8f730998ca4324921a010b9/xxhash-3.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82085c2abec437abebf457c1d12fccb30cc8b3774a0814872511f0f0562c768c", size = 428324 }, + { url = "https://files.pythonhosted.org/packages/b4/0e/15c243775342ce840b9ba34aceace06a1148fa1630cd8ca269e3223987f5/xxhash-3.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07fda5de378626e502b42b311b049848c2ef38784d0d67b6f30bb5008642f8eb", size = 194370 }, + { url = "https://files.pythonhosted.org/packages/87/a1/b028bb02636dfdc190da01951d0703b3d904301ed0ef6094d948983bef0e/xxhash-3.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c279f0d2b34ef15f922b77966640ade58b4ccdfef1c4d94b20f2a364617a493f", size = 207911 }, + { url = "https://files.pythonhosted.org/packages/80/d5/73c73b03fc0ac73dacf069fdf6036c9abad82de0a47549e9912c955ab449/xxhash-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:89e66ceed67b213dec5a773e2f7a9e8c58f64daeb38c7859d8815d2c89f39ad7", size = 216352 }, + { url = "https://files.pythonhosted.org/packages/b6/2a/5043dba5ddbe35b4fe6ea0a111280ad9c3d4ba477dd0f2d1fe1129bda9d0/xxhash-3.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bcd51708a633410737111e998ceb3b45d3dbc98c0931f743d9bb0a209033a326", size = 203410 }, + { url = "https://files.pythonhosted.org/packages/a2/b2/9a8ded888b7b190aed75b484eb5c853ddd48aa2896e7b59bbfbce442f0a1/xxhash-3.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ff2c0a34eae7df88c868be53a8dd56fbdf592109e21d4bfa092a27b0bf4a7bf", size = 210322 }, + { url = "https://files.pythonhosted.org/packages/98/62/440083fafbc917bf3e4b67c2ade621920dd905517e85631c10aac955c1d2/xxhash-3.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e28503dccc7d32e0b9817aa0cbfc1f45f563b2c995b7a66c4c8a0d232e840c7", size = 414725 }, + { url = "https://files.pythonhosted.org/packages/75/db/009206f7076ad60a517e016bb0058381d96a007ce3f79fa91d3010f49cc2/xxhash-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a6c50017518329ed65a9e4829154626f008916d36295b6a3ba336e2458824c8c", size = 192070 }, + { url = "https://files.pythonhosted.org/packages/1f/6d/c61e0668943a034abc3a569cdc5aeae37d686d9da7e39cf2ed621d533e36/xxhash-3.5.0-cp313-cp313-win32.whl", hash = "sha256:53a068fe70301ec30d868ece566ac90d873e3bb059cf83c32e76012c889b8637", size = 30172 }, + { url = "https://files.pythonhosted.org/packages/96/14/8416dce965f35e3d24722cdf79361ae154fa23e2ab730e5323aa98d7919e/xxhash-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:80babcc30e7a1a484eab952d76a4f4673ff601f54d5142c26826502740e70b43", size = 30041 }, + { url = "https://files.pythonhosted.org/packages/27/ee/518b72faa2073f5aa8e3262408d284892cb79cf2754ba0c3a5870645ef73/xxhash-3.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:4811336f1ce11cac89dcbd18f3a25c527c16311709a89313c3acaf771def2d4b", size = 26801 }, + { url = "https://files.pythonhosted.org/packages/d4/f6/531dd6858adf8877675270b9d6989b6dacfd1c2d7135b17584fc29866df3/xxhash-3.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc8cdd7f33d57f0468b0614ae634cc38ab9202c6957a60e31d285a71ebe0301", size = 31971 }, + { url = "https://files.pythonhosted.org/packages/7c/a8/b2a42b6c9ae46e233f474f3d307c2e7bca8d9817650babeca048d2ad01d6/xxhash-3.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e0c48b6300cd0b0106bf49169c3e0536408dfbeb1ccb53180068a18b03c662ab", size = 30801 }, + { url = "https://files.pythonhosted.org/packages/b4/92/9ac297e3487818f429bcf369c1c6a097edf5b56ed6fc1feff4c1882e87ef/xxhash-3.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe1a92cfbaa0a1253e339ccec42dbe6db262615e52df591b68726ab10338003f", size = 220644 }, + { url = "https://files.pythonhosted.org/packages/86/48/c1426dd3c86fc4a52f983301867463472f6a9013fb32d15991e60c9919b6/xxhash-3.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33513d6cc3ed3b559134fb307aae9bdd94d7e7c02907b37896a6c45ff9ce51bd", size = 200021 }, + { url = "https://files.pythonhosted.org/packages/f3/de/0ab8c79993765c94fc0d0c1a22b454483c58a0161e1b562f58b654f47660/xxhash-3.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eefc37f6138f522e771ac6db71a6d4838ec7933939676f3753eafd7d3f4c40bc", size = 428217 }, + { url = "https://files.pythonhosted.org/packages/b4/b4/332647451ed7d2c021294b7c1e9c144dbb5586b1fb214ad4f5a404642835/xxhash-3.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a606c8070ada8aa2a88e181773fa1ef17ba65ce5dd168b9d08038e2a61b33754", size = 193868 }, + { url = "https://files.pythonhosted.org/packages/f4/1c/a42c0a6cac752f84f7b44a90d1a9fa9047cf70bdba5198a304fde7cc471f/xxhash-3.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42eca420c8fa072cc1dd62597635d140e78e384a79bb4944f825fbef8bfeeef6", size = 207403 }, + { url = "https://files.pythonhosted.org/packages/c4/d7/04e1b0daae9dc9b02c73c1664cc8aa527498c3f66ccbc586eeb25bbe9f14/xxhash-3.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:604253b2143e13218ff1ef0b59ce67f18b8bd1c4205d2ffda22b09b426386898", size = 215978 }, + { url = "https://files.pythonhosted.org/packages/c4/f4/05e15e67505228fc19ee98a79e427b3a0b9695f5567cd66ced5d66389883/xxhash-3.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6e93a5ad22f434d7876665444a97e713a8f60b5b1a3521e8df11b98309bff833", size = 202416 }, + { url = "https://files.pythonhosted.org/packages/94/fb/e9028d3645bba5412a09de13ee36df276a567e60bdb31d499dafa46d76ae/xxhash-3.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:7a46e1d6d2817ba8024de44c4fd79913a90e5f7265434cef97026215b7d30df6", size = 209853 }, + { url = "https://files.pythonhosted.org/packages/02/2c/18c6a622429368274739372d2f86c8125413ec169025c7d8ffb051784bba/xxhash-3.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:30eb2efe6503c379b7ab99c81ba4a779748e3830241f032ab46bd182bf5873af", size = 413926 }, + { url = "https://files.pythonhosted.org/packages/72/bb/5b55c391084a0321c3809632a018b9b657e59d5966289664f85a645942ac/xxhash-3.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c8aa771ff2c13dd9cda8166d685d7333d389fae30a4d2bb39d63ab5775de8606", size = 191156 }, + { url = "https://files.pythonhosted.org/packages/86/2b/915049db13401792fec159f57e4f4a5ca7a9768e83ef71d6645b9d0cd749/xxhash-3.5.0-cp39-cp39-win32.whl", hash = "sha256:5ed9ebc46f24cf91034544b26b131241b699edbfc99ec5e7f8f3d02d6eb7fba4", size = 30122 }, + { url = "https://files.pythonhosted.org/packages/d5/87/382ef7b24917d7cf4c540ee30f29b283bc87ac5893d2f89b23ea3cdf7d77/xxhash-3.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:220f3f896c6b8d0316f63f16c077d52c412619e475f9372333474ee15133a558", size = 30021 }, + { url = "https://files.pythonhosted.org/packages/e2/47/d06b24e2d9c3dcabccfd734d11b5bbebfdf59ceac2c61509d8205dd20ac6/xxhash-3.5.0-cp39-cp39-win_arm64.whl", hash = "sha256:a7b1d8315d9b5e9f89eb2933b73afae6ec9597a258d52190944437158b49d38e", size = 26780 }, + { url = "https://files.pythonhosted.org/packages/ab/9a/233606bada5bd6f50b2b72c45de3d9868ad551e83893d2ac86dc7bb8553a/xxhash-3.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2014c5b3ff15e64feecb6b713af12093f75b7926049e26a580e94dcad3c73d8c", size = 29732 }, + { url = "https://files.pythonhosted.org/packages/0c/67/f75276ca39e2c6604e3bee6c84e9db8a56a4973fde9bf35989787cf6e8aa/xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fab81ef75003eda96239a23eda4e4543cedc22e34c373edcaf744e721a163986", size = 36214 }, + { url = "https://files.pythonhosted.org/packages/0f/f8/f6c61fd794229cc3848d144f73754a0c107854372d7261419dcbbd286299/xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2febf914ace002132aa09169cc572e0d8959d0f305f93d5828c4836f9bc5a6", size = 32020 }, + { url = "https://files.pythonhosted.org/packages/79/d3/c029c99801526f859e6b38d34ab87c08993bf3dcea34b11275775001638a/xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d3a10609c51da2a1c0ea0293fc3968ca0a18bd73838455b5bca3069d7f8e32b", size = 40515 }, + { url = "https://files.pythonhosted.org/packages/62/e3/bef7b82c1997579c94de9ac5ea7626d01ae5858aa22bf4fcb38bf220cb3e/xxhash-3.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a74f23335b9689b66eb6dbe2a931a88fcd7a4c2cc4b1cb0edba8ce381c7a1da", size = 30064 }, + { url = "https://files.pythonhosted.org/packages/c2/56/30d3df421814947f9d782b20c9b7e5e957f3791cbd89874578011daafcbd/xxhash-3.5.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:531af8845aaadcadf951b7e0c1345c6b9c68a990eeb74ff9acd8501a0ad6a1c9", size = 29734 }, + { url = "https://files.pythonhosted.org/packages/82/dd/3c42a1f022ad0d82c852d3cb65493ebac03dcfa8c994465a5fb052b00e3c/xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ce379bcaa9fcc00f19affa7773084dd09f5b59947b3fb47a1ceb0179f91aaa1", size = 36216 }, + { url = "https://files.pythonhosted.org/packages/b2/40/8f902ab3bebda228a9b4de69eba988280285a7f7f167b942bc20bb562df9/xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd1b2281d01723f076df3c8188f43f2472248a6b63118b036e641243656b1b0f", size = 32042 }, + { url = "https://files.pythonhosted.org/packages/db/87/bd06beb8ccaa0e9e577c9b909a49cfa5c5cd2ca46034342d72dd9ce5bc56/xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c770750cc80e8694492244bca7251385188bc5597b6a39d98a9f30e8da984e0", size = 40516 }, + { url = "https://files.pythonhosted.org/packages/bb/f8/505385e2fbd753ddcaafd5550eabe86f6232cbebabad3b2508d411b19153/xxhash-3.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b150b8467852e1bd844387459aa6fbe11d7f38b56e901f9f3b3e6aba0d660240", size = 30108 }, +] + +[[package]] +name = "yarl" +version = "1.17.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4b/d5/0d0481857de42a44ba4911f8010d4b361dc26487f48d5503c66a797cff48/yarl-1.17.2.tar.gz", hash = "sha256:753eaaa0c7195244c84b5cc159dc8204b7fd99f716f11198f999f2332a86b178", size = 178947 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/69/efe2486932ec0b09248e6b13ee41872ad3cbbe7f135c166f533872bf1787/yarl-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:93771146ef048b34201bfa382c2bf74c524980870bb278e6df515efaf93699ff", size = 140927 }, + { url = "https://files.pythonhosted.org/packages/4c/23/3501e49d53ef37453875abd93c13152e217108421d54c92ff9c038322bb7/yarl-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8281db240a1616af2f9c5f71d355057e73a1409c4648c8949901396dc0a3c151", size = 93836 }, + { url = "https://files.pythonhosted.org/packages/9d/20/379d016139517d0fab03739b40f6e47e039fca52bda5c0afac2ac104fa0f/yarl-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:170ed4971bf9058582b01a8338605f4d8c849bd88834061e60e83b52d0c76870", size = 91656 }, + { url = "https://files.pythonhosted.org/packages/59/87/5291ec5ae0ae16f93617aef31ae3223576e3b4913ab30d9d084c435f13ee/yarl-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc61b005f6521fcc00ca0d1243559a5850b9dd1e1fe07b891410ee8fe192d0c0", size = 314833 }, + { url = "https://files.pythonhosted.org/packages/0c/bc/a1ee1e01259800a73108313684de20f3d53dd5e62278d6ee873792362e66/yarl-1.17.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:871e1b47eec7b6df76b23c642a81db5dd6536cbef26b7e80e7c56c2fd371382e", size = 329964 }, + { url = "https://files.pythonhosted.org/packages/02/15/a0d55fe89c968c9a55c7c88789df05739b2f45b56e874984de085cac2b70/yarl-1.17.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a58a2f2ca7aaf22b265388d40232f453f67a6def7355a840b98c2d547bd037f", size = 326406 }, + { url = "https://files.pythonhosted.org/packages/b6/c0/920c1418d996574a537adae53c394d7a218b0d1aa318ff7765009cc06266/yarl-1.17.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:736bb076f7299c5c55dfef3eb9e96071a795cb08052822c2bb349b06f4cb2e0a", size = 319176 }, + { url = "https://files.pythonhosted.org/packages/f7/b4/4fc5a63af3c44331dc1a2f152aa526ee88045cfb0b932d10f0b60984773d/yarl-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8fd51299e21da709eabcd5b2dd60e39090804431292daacbee8d3dabe39a6bc0", size = 309704 }, + { url = "https://files.pythonhosted.org/packages/72/b2/99a7a35b363c14f3add70a213f520679823ea511fbfd306904307b0bfc34/yarl-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:358dc7ddf25e79e1cc8ee16d970c23faee84d532b873519c5036dbb858965795", size = 319256 }, + { url = "https://files.pythonhosted.org/packages/aa/ba/c1c1b8990a26dacfb366a41a77a96428247ab9e47cde41c7d632e1370f23/yarl-1.17.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:50d866f7b1a3f16f98603e095f24c0eeba25eb508c85a2c5939c8b3870ba2df8", size = 321211 }, + { url = "https://files.pythonhosted.org/packages/44/1b/5db76f87b722ba9fa24b898057a283bc5166e063fdf08018b1ce59f2c389/yarl-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8b9c4643e7d843a0dca9cd9d610a0876e90a1b2cbc4c5ba7930a0d90baf6903f", size = 324306 }, + { url = "https://files.pythonhosted.org/packages/a9/93/035008cbd7bddc5db5680b6d3a72172f4c13dd20198264a269f7905d66cd/yarl-1.17.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d63123bfd0dce5f91101e77c8a5427c3872501acece8c90df457b486bc1acd47", size = 336549 }, + { url = "https://files.pythonhosted.org/packages/69/33/977e35cbbb54e41655134dfdbf32ac68ca6429b8f88eb3738c48e67e558c/yarl-1.17.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:4e76381be3d8ff96a4e6c77815653063e87555981329cf8f85e5be5abf449021", size = 337649 }, + { url = "https://files.pythonhosted.org/packages/8f/74/75c539a55d8b2708d4e0f9e22adc1365e06c1c1d0f80e1f24f85f80d99d1/yarl-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:734144cd2bd633a1516948e477ff6c835041c0536cef1d5b9a823ae29899665b", size = 331365 }, + { url = "https://files.pythonhosted.org/packages/d4/69/900ff74bed3f66528bb5ccb523ed5f8a29baed27ee8be552744ed6d146bf/yarl-1.17.2-cp310-cp310-win32.whl", hash = "sha256:26bfb6226e0c157af5da16d2d62258f1ac578d2899130a50433ffee4a5dfa673", size = 83793 }, + { url = "https://files.pythonhosted.org/packages/4c/ec/a4bf3e3adfc62a72af70475e2126c71f693c05321bfd38661dc98ecb270f/yarl-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:76499469dcc24759399accd85ec27f237d52dec300daaca46a5352fcbebb1071", size = 89970 }, + { url = "https://files.pythonhosted.org/packages/1a/3a/56d6c650a51f9f44b5d848c0c2f2d994aced6fdb8bc993641f913f286eb4/yarl-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:792155279dc093839e43f85ff7b9b6493a8eaa0af1f94f1f9c6e8f4de8c63500", size = 141027 }, + { url = "https://files.pythonhosted.org/packages/6a/fa/3d180fde00a1825db11c9f6539dc8a52edd09838f3c18d484cdceea289c2/yarl-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:38bc4ed5cae853409cb193c87c86cd0bc8d3a70fd2268a9807217b9176093ac6", size = 93821 }, + { url = "https://files.pythonhosted.org/packages/19/71/f7241b745f0f9b3120de1b2a63c08b5bae5ec6d42890026a58545a068c4e/yarl-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4a8c83f6fcdc327783bdc737e8e45b2e909b7bd108c4da1892d3bc59c04a6d84", size = 91759 }, + { url = "https://files.pythonhosted.org/packages/c1/75/be5ef48a356966fa15f98002d7f3bfbed2bc71b6f815f77914147c1607c4/yarl-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c6d5fed96f0646bfdf698b0a1cebf32b8aae6892d1bec0c5d2d6e2df44e1e2d", size = 340120 }, + { url = "https://files.pythonhosted.org/packages/73/4e/61ac73e26e9d184a8f5186c764a039c682fdbe71be84a5eaf3dca1b459f4/yarl-1.17.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:782ca9c58f5c491c7afa55518542b2b005caedaf4685ec814fadfcee51f02493", size = 356095 }, + { url = "https://files.pythonhosted.org/packages/98/3b/3db2fcc6eba18c47108f5c4d737818ca266086e9fb11675e268ebac33f41/yarl-1.17.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff6af03cac0d1a4c3c19e5dcc4c05252411bf44ccaa2485e20d0a7c77892ab6e", size = 353460 }, + { url = "https://files.pythonhosted.org/packages/e1/fc/01eba5b0ff6c7d49e86d77561a3d89493b4bbae8cc91bd137ed3dfd2c4b2/yarl-1.17.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a3f47930fbbed0f6377639503848134c4aa25426b08778d641491131351c2c8", size = 343630 }, + { url = "https://files.pythonhosted.org/packages/52/a3/2823941b1c3e13e6442cefcb5fec60265c7c5fbcf6361bd8056505ac8f7f/yarl-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1fa68a3c921365c5745b4bd3af6221ae1f0ea1bf04b69e94eda60e57958907f", size = 335610 }, + { url = "https://files.pythonhosted.org/packages/13/71/6d54fa13ac34207083fd7c3b6b3a218503dfdd7d14d9915dd5e830e5e514/yarl-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:187df91395c11e9f9dc69b38d12406df85aa5865f1766a47907b1cc9855b6303", size = 347466 }, + { url = "https://files.pythonhosted.org/packages/50/5e/0fe426c43d86e32193e02a3b34f1a5179e87be9c95eec722da2386b00f9d/yarl-1.17.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:93d1c8cc5bf5df401015c5e2a3ce75a5254a9839e5039c881365d2a9dcfc6dc2", size = 345927 }, + { url = "https://files.pythonhosted.org/packages/62/a0/bf973a0c1912f9993e3db9ac270e18a3a71ca83e495ee52a3d25e6a64253/yarl-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:11d86c6145ac5c706c53d484784cf504d7d10fa407cb73b9d20f09ff986059ef", size = 349662 }, + { url = "https://files.pythonhosted.org/packages/a2/9d/02a574f7281a48e95b3a9d7ae4ea069ad617356492abaebb02ac861b037a/yarl-1.17.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c42774d1d1508ec48c3ed29e7b110e33f5e74a20957ea16197dbcce8be6b52ba", size = 361601 }, + { url = "https://files.pythonhosted.org/packages/5b/56/7887ea130159ff3354423173ba815963da8f1cba2df054e06d561d08e179/yarl-1.17.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8e589379ef0407b10bed16cc26e7392ef8f86961a706ade0a22309a45414d7", size = 365767 }, + { url = "https://files.pythonhosted.org/packages/4d/3e/84f6d161f74c2b478d774e35b5200981bb373846fc5420880607113fbba5/yarl-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1056cadd5e850a1c026f28e0704ab0a94daaa8f887ece8dfed30f88befb87bb0", size = 358643 }, + { url = "https://files.pythonhosted.org/packages/fd/d5/efe4dce200bfe64eab34f550548805350d46e95f5e24b51a46fe71d0f526/yarl-1.17.2-cp311-cp311-win32.whl", hash = "sha256:be4c7b1c49d9917c6e95258d3d07f43cfba2c69a6929816e77daf322aaba6628", size = 83884 }, + { url = "https://files.pythonhosted.org/packages/9b/24/fa2fe6ff50a49ec059698ef3738b00531977473ca1dcf6225db29d07404f/yarl-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:ac8eda86cc75859093e9ce390d423aba968f50cf0e481e6c7d7d63f90bae5c9c", size = 90514 }, + { url = "https://files.pythonhosted.org/packages/47/d0/aa07433c3a8958bc7639e7d7cb2d6fbad204b40e59b6ec7c95c51ef891d8/yarl-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dd90238d3a77a0e07d4d6ffdebc0c21a9787c5953a508a2231b5f191455f31e9", size = 142115 }, + { url = "https://files.pythonhosted.org/packages/44/ce/0be3f77e99aded7b949ca2c822203309ef20d5ec0dd4470056e21dabcdb1/yarl-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c74f0b0472ac40b04e6d28532f55cac8090e34c3e81f118d12843e6df14d0909", size = 94435 }, + { url = "https://files.pythonhosted.org/packages/ae/4e/e22fb21928889837ebf97dd04c7c523cad992edb1499c8cabbd438e8e93a/yarl-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d486ddcaca8c68455aa01cf53d28d413fb41a35afc9f6594a730c9779545876", size = 92264 }, + { url = "https://files.pythonhosted.org/packages/95/5b/4f54cac3711a76c22c4c47cedb216fdd6296ad5dafab4bc64da2e417c4f6/yarl-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25b7e93f5414b9a983e1a6c1820142c13e1782cc9ed354c25e933aebe97fcf2", size = 331820 }, + { url = "https://files.pythonhosted.org/packages/5b/8b/ab46adcf981c406a7b8cc47593505ac64cf0c7dbfa233900da6c37288042/yarl-1.17.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a0baff7827a632204060f48dca9e63fbd6a5a0b8790c1a2adfb25dc2c9c0d50", size = 341798 }, + { url = "https://files.pythonhosted.org/packages/54/cc/db5d3ddcc8d2b34775fef2c5b3a50332f822e70d5828ab9216e1ea0e9033/yarl-1.17.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:460024cacfc3246cc4d9f47a7fc860e4fcea7d1dc651e1256510d8c3c9c7cde0", size = 341445 }, + { url = "https://files.pythonhosted.org/packages/ec/1f/c45d9c02111389f71e6d9b49dff8744f7987b174da974619c4815f2d671d/yarl-1.17.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5870d620b23b956f72bafed6a0ba9a62edb5f2ef78a8849b7615bd9433384171", size = 336391 }, + { url = "https://files.pythonhosted.org/packages/9b/11/6946a16258ae9fcea4da2e71c0d5d9f21868821109ceca2884d6bb137fc1/yarl-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2941756754a10e799e5b87e2319bbec481ed0957421fba0e7b9fb1c11e40509f", size = 325233 }, + { url = "https://files.pythonhosted.org/packages/ae/83/72453e6e570fd6948d21348350c3cf2cd811dc0cc9b7779a99e5a57554a3/yarl-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9611b83810a74a46be88847e0ea616794c406dbcb4e25405e52bff8f4bee2d0a", size = 343952 }, + { url = "https://files.pythonhosted.org/packages/6e/91/4de2fecb15129a0ecb6844b7693f18c6616586b801635e30ef0d232bc0e2/yarl-1.17.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cd7e35818d2328b679a13268d9ea505c85cd773572ebb7a0da7ccbca77b6a52e", size = 340256 }, + { url = "https://files.pythonhosted.org/packages/60/d4/6dd9959a6499a8d52ca48bbe139fc84ad3291697c681758c4851f5375972/yarl-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6b981316fcd940f085f646b822c2ff2b8b813cbd61281acad229ea3cbaabeb6b", size = 345975 }, + { url = "https://files.pythonhosted.org/packages/1f/97/76ac1bc71faa71101ed8e0d902471124d8d9d5adc3faa3aa9a0bd0989e54/yarl-1.17.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:688058e89f512fb7541cb85c2f149c292d3fa22f981d5a5453b40c5da49eb9e8", size = 359359 }, + { url = "https://files.pythonhosted.org/packages/1b/d7/47ffcb4ea188af16b6b0f6ae1b53ed620a81a7180b92f68a551750f5c812/yarl-1.17.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56afb44a12b0864d17b597210d63a5b88915d680f6484d8d202ed68ade38673d", size = 363988 }, + { url = "https://files.pythonhosted.org/packages/30/d6/385e830d3b9efcd18bcdd212d5c752dbcc9f1c48bde00a256f7401f8b32b/yarl-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:17931dfbb84ae18b287279c1f92b76a3abcd9a49cd69b92e946035cff06bcd20", size = 357342 }, + { url = "https://files.pythonhosted.org/packages/ae/5b/6b5e78e7a71698b2b4830e83aa71e86c85357dbf13c617c8515c03d019a9/yarl-1.17.2-cp312-cp312-win32.whl", hash = "sha256:ff8d95e06546c3a8c188f68040e9d0360feb67ba8498baf018918f669f7bc39b", size = 83581 }, + { url = "https://files.pythonhosted.org/packages/bd/fa/a70635eabe46ba55032bd1e1c2561067f35036b614299f09b15cdef167ee/yarl-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:4c840cc11163d3c01a9d8aad227683c48cd3e5be5a785921bcc2a8b4b758c4f3", size = 89882 }, + { url = "https://files.pythonhosted.org/packages/29/64/09e6b953f304caaf50a27d7702cdbf7cc5508dd3a5fff8df1e2af05efeb6/yarl-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3294f787a437cb5d81846de3a6697f0c35ecff37a932d73b1fe62490bef69211", size = 140262 }, + { url = "https://files.pythonhosted.org/packages/81/08/1162bea6b991b51d8cb74aa888663fad07f1be959b3a2aeed2a3009e4484/yarl-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f1e7fedb09c059efee2533119666ca7e1a2610072076926fa028c2ba5dfeb78c", size = 93616 }, + { url = "https://files.pythonhosted.org/packages/d1/7e/a8fd1cbfdd1420b8b40a17f94609c762dff695ecdcf98d96aa700cb16b4d/yarl-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:da9d3061e61e5ae3f753654813bc1cd1c70e02fb72cf871bd6daf78443e9e2b1", size = 91447 }, + { url = "https://files.pythonhosted.org/packages/27/fa/2800adcec8ca5833f6737b82e9a14c779c868d2652ff14e7b1346d24554e/yarl-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91c012dceadc695ccf69301bfdccd1fc4472ad714fe2dd3c5ab4d2046afddf29", size = 333095 }, + { url = "https://files.pythonhosted.org/packages/bc/22/195064102b1ff995f3f84b6c15cd7143b95e37b3a201a8ee7ef327d5cb27/yarl-1.17.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f11fd61d72d93ac23718d393d2a64469af40be2116b24da0a4ca6922df26807e", size = 343865 }, + { url = "https://files.pythonhosted.org/packages/7b/d5/08a9593ad09276087470cdf957b8073b90e1b5d37b7537522ae393cbab05/yarl-1.17.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46c465ad06971abcf46dd532f77560181387b4eea59084434bdff97524444032", size = 344881 }, + { url = "https://files.pythonhosted.org/packages/bf/30/05071e72503f1f326ac821dbd5b0fc757c4d643ee0f127236a784a3e0173/yarl-1.17.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef6eee1a61638d29cd7c85f7fd3ac7b22b4c0fabc8fd00a712b727a3e73b0685", size = 338843 }, + { url = "https://files.pythonhosted.org/packages/ac/37/a65fc94ca089b827775c90f40c7c94b5b1d49bfee041ac528a4c529f2c10/yarl-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4434b739a8a101a837caeaa0137e0e38cb4ea561f39cb8960f3b1e7f4967a3fc", size = 326140 }, + { url = "https://files.pythonhosted.org/packages/e2/5c/eb0ecd48cc46d14589ef3ce18664e2390d0702a3560b1956c195996580ae/yarl-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:752485cbbb50c1e20908450ff4f94217acba9358ebdce0d8106510859d6eb19a", size = 344943 }, + { url = "https://files.pythonhosted.org/packages/03/44/f5d9ccc62744f7df157dfa68d2dd8bf64dba54ced26d6f7bc69a2e6d18dd/yarl-1.17.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:17791acaa0c0f89323c57da7b9a79f2174e26d5debbc8c02d84ebd80c2b7bff8", size = 341393 }, + { url = "https://files.pythonhosted.org/packages/5e/5d/8c9fd78bf0c43f4152daa70f4f8335e71fbca22b5e8e2f39b81dcf6dbca8/yarl-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5c6ea72fe619fee5e6b5d4040a451d45d8175f560b11b3d3e044cd24b2720526", size = 346993 }, + { url = "https://files.pythonhosted.org/packages/b5/0d/0a25507300a288d7109ac6f4dd9ec51427fc2052ab5be7bc1a6b0dad3a6b/yarl-1.17.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db5ac3871ed76340210fe028f535392f097fb31b875354bcb69162bba2632ef4", size = 359480 }, + { url = "https://files.pythonhosted.org/packages/36/be/1f8e1f367ce35295612057b5c47bedf77d60bc83b1305232a6810103c7f6/yarl-1.17.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7a1606ba68e311576bcb1672b2a1543417e7e0aa4c85e9e718ba6466952476c0", size = 365716 }, + { url = "https://files.pythonhosted.org/packages/51/c4/1e2af7b0fe8488e0b487cb2114cb00b310ac745520670964b42074174073/yarl-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9bc27dd5cfdbe3dc7f381b05e6260ca6da41931a6e582267d5ca540270afeeb2", size = 359866 }, + { url = "https://files.pythonhosted.org/packages/37/ea/615633dc2306ad01436cdbcd255978f13cba752e1b2b73ecdc0f785bed2f/yarl-1.17.2-cp313-cp313-win32.whl", hash = "sha256:52492b87d5877ec405542f43cd3da80bdcb2d0c2fbc73236526e5f2c28e6db28", size = 309638 }, + { url = "https://files.pythonhosted.org/packages/ff/b3/d8d49f6320abd7f253646c6ac8582d936fed7d7b11632fc96bd7ca639e68/yarl-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:8e1bf59e035534ba4077f5361d8d5d9194149f9ed4f823d1ee29ef3e8964ace3", size = 315209 }, + { url = "https://files.pythonhosted.org/packages/e0/28/1e84a20471bb154f0f1e728dc560cab3ebc68a8332e7b8dce5253712f555/yarl-1.17.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c556fbc6820b6e2cda1ca675c5fa5589cf188f8da6b33e9fc05b002e603e44fa", size = 142253 }, + { url = "https://files.pythonhosted.org/packages/5e/39/9ea5a08de2c3ca222437fe50d8e971b0d25d6c05e458a85c18f5462f8d75/yarl-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f2f44a4247461965fed18b2573f3a9eb5e2c3cad225201ee858726cde610daca", size = 94459 }, + { url = "https://files.pythonhosted.org/packages/87/04/d6ec141d03e83f6106285dfe2763295a03731246ff08cc0d698a2ad24b9d/yarl-1.17.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3a3ede8c248f36b60227eb777eac1dbc2f1022dc4d741b177c4379ca8e75571a", size = 92267 }, + { url = "https://files.pythonhosted.org/packages/37/e4/813ad23652ecc1710dee615b06769a1b2f436644906e997b17f0648e8872/yarl-1.17.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2654caaf5584449d49c94a6b382b3cb4a246c090e72453493ea168b931206a4d", size = 316816 }, + { url = "https://files.pythonhosted.org/packages/41/e5/2fcf8fb2daf95b3f7a1060ddc929f857a478565997480131616c7ba02bcd/yarl-1.17.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d41c684f286ce41fa05ab6af70f32d6da1b6f0457459a56cf9e393c1c0b2217", size = 336490 }, + { url = "https://files.pythonhosted.org/packages/d8/34/e79d482e7a9cdfb757995630a2b2f5b7f04a97cc0dce5042e04d9b18e290/yarl-1.17.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2270d590997445a0dc29afa92e5534bfea76ba3aea026289e811bf9ed4b65a7f", size = 331166 }, + { url = "https://files.pythonhosted.org/packages/f8/d0/9973b1f127f7a419143877baf89d39767c83b828f492b4cac9fa085f85fd/yarl-1.17.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18662443c6c3707e2fc7fad184b4dc32dd428710bbe72e1bce7fe1988d4aa654", size = 320961 }, + { url = "https://files.pythonhosted.org/packages/32/96/94057fc216b8b3280b29777640f3925a815d3dc5e9dd8e653d4b372b87e8/yarl-1.17.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75ac158560dec3ed72f6d604c81090ec44529cfb8169b05ae6fcb3e986b325d9", size = 313047 }, + { url = "https://files.pythonhosted.org/packages/e5/7d/6cbca963edda288086bda81a17cb45ef90d93169c50a1b758fd757f663ef/yarl-1.17.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1fee66b32e79264f428dc8da18396ad59cc48eef3c9c13844adec890cd339db5", size = 324499 }, + { url = "https://files.pythonhosted.org/packages/56/ec/227ef54c7ac228935a07af852953c05c7b4a9fe897c442a8b6df376ead9e/yarl-1.17.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:585ce7cd97be8f538345de47b279b879e091c8b86d9dbc6d98a96a7ad78876a3", size = 322159 }, + { url = "https://files.pythonhosted.org/packages/8e/41/bb22f678c568dc6a3c24adc5162de989657787fb44e84d7aa509d5c05e54/yarl-1.17.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c019abc2eca67dfa4d8fb72ba924871d764ec3c92b86d5b53b405ad3d6aa56b0", size = 332292 }, + { url = "https://files.pythonhosted.org/packages/30/4f/def6b265ff94a84dd355c63edcb346ebb48514b6501c26a8bcc47413ef1d/yarl-1.17.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c6e659b9a24d145e271c2faf3fa6dd1fcb3e5d3f4e17273d9e0350b6ab0fe6e2", size = 339459 }, + { url = "https://files.pythonhosted.org/packages/ff/a9/484e36d6cf9c646e1432b733f0f6106126d93a06a86236a05a284da3b9ce/yarl-1.17.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:d17832ba39374134c10e82d137e372b5f7478c4cceeb19d02ae3e3d1daed8721", size = 340468 }, + { url = "https://files.pythonhosted.org/packages/f5/87/512fc40dcbc00828075d370bfbb7be947ff689f229c81458d23b61db6d3d/yarl-1.17.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bc3003710e335e3f842ae3fd78efa55f11a863a89a72e9a07da214db3bf7e1f8", size = 336094 }, + { url = "https://files.pythonhosted.org/packages/21/5e/0222d36f8b0ed7d137c34c211ce320fae89fca05b43677b890f9357830d2/yarl-1.17.2-cp39-cp39-win32.whl", hash = "sha256:f5ffc6b7ace5b22d9e73b2a4c7305740a339fbd55301d52735f73e21d9eb3130", size = 84314 }, + { url = "https://files.pythonhosted.org/packages/39/39/5b8968af4fc005ae7cdf614f9f413b586511ae38e9bd01566638a7048737/yarl-1.17.2-cp39-cp39-win_amd64.whl", hash = "sha256:48e424347a45568413deec6f6ee2d720de2cc0385019bedf44cd93e8638aa0ed", size = 90453 }, + { url = "https://files.pythonhosted.org/packages/80/01/7536ea609df5afce0c0d3c00e5843f0005d65226b6a61028310ac9673a07/yarl-1.17.2-py3-none-any.whl", hash = "sha256:dd7abf4f717e33b7487121faf23560b3a50924f80e4bef62b22dab441ded8f3b", size = 44583 }, +] + +[[package]] +name = "zipp" +version = "3.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/50/bad581df71744867e9468ebd0bcd6505de3b275e06f202c2cb016e3ff56f/zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", size = 24545 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/1a/7e4798e9339adc931158c9d69ecc34f5e6791489d469f5e50ec15e35f458/zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931", size = 9630 }, +]