From 14f9cbf32d3e69e9ca18d9f8c0ef80d526277f7b Mon Sep 17 00:00:00 2001 From: spencer Date: Tue, 27 Aug 2024 16:16:41 +0100 Subject: [PATCH 01/17] chore(consume): return pytest exit-code from consume commands (#766) --- docs/CHANGELOG.md | 1 + src/cli/pytest_commands/consume.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 0ee4a52a63..780ea4b45d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -29,6 +29,7 @@ Test fixtures for use by clients are available for each release on the [Github r - ✨ Added optional parameter to all `with_all_*` markers to specify a lambda function that filters the parametrized values ([#739](https://github.com/ethereum/execution-spec-tests/pull/739)). - ✨ Added [`extend_with_defaults` utility function](https://ethereum.github.io/execution-spec-tests/main/writing_tests/writing_a_new_test/#ethereum_test_tools.utility.pytest.extend_with_defaults), which helps extend test case parameter sets with default values. `@pytest.mark.parametrize` ([#739](https://github.com/ethereum/execution-spec-tests/pull/739)). - ✨ Added `Container.Init` to `ethereum_test_types.EOF.V1` package, which allows generation of an EOF init container more easily ([#739](https://github.com/ethereum/execution-spec-tests/pull/739)). +- 🐞 Fixed `consume` exit code return values, ensuring that pytest's return value is correctly propagated to the shell. This allows the shell to accurately reflect the test results (e.g., failures) based on the pytest exit code ([#765](https://github.com/ethereum/execution-spec-tests/pull/765)). ### 🔧 EVM Tools diff --git a/src/cli/pytest_commands/consume.py b/src/cli/pytest_commands/consume.py index d170ad1b57..28b28e4ca4 100644 --- a/src/cli/pytest_commands/consume.py +++ b/src/cli/pytest_commands/consume.py @@ -101,9 +101,10 @@ def command(pytest_args: List[str], help_flag: bool, pytest_help_flag: bool) -> if is_hive and not any(arg.startswith("--hive-session-temp-folder") for arg in args): with TemporaryDirectory() as temp_dir: args.extend(["--hive-session-temp-folder", temp_dir]) - pytest.main(args) + result = pytest.main(args) else: - pytest.main(args) + result = pytest.main(args) + sys.exit(result) command.__doc__ = func.__doc__ return command From aee35f0e132fd15783cc70be9b9b6a03920d1204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 27 Aug 2024 20:56:34 +0200 Subject: [PATCH 02/17] new(tests): EOF - EIP-7620: migrate "embedded container" tests (#763) * new(tests): migrate EOF "embedded container" tests Migrate EOFTests/efValidation/EOF1_embedded_container_.json. * fixup! rename migrated tests ids --- converted-ethereum-tests.txt | 1 + .../test_subcontainer_validation.py | 117 +++++++++++++++--- 2 files changed, 98 insertions(+), 20 deletions(-) diff --git a/converted-ethereum-tests.txt b/converted-ethereum-tests.txt index 6ad4709e99..e49231997d 100644 --- a/converted-ethereum-tests.txt +++ b/converted-ethereum-tests.txt @@ -5,6 +5,7 @@ GeneralStateTests/stCreate2/call_then_create2_successful_then_returndatasize.jso ([#598](https://github.com/ethereum/execution-spec-tests/pull/598)) EOFTests/EIP3540/validInvalid.json +EOFTests/efValidation/EOF1_embedded_container_.json EOFTests/efValidation/EOF1_eofcreate_valid_.json EOFTests/efValidation/EOF1_section_order_.json EOFTests/efValidation/EOF1_truncated_section_.json diff --git a/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py b/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py index 1b5e586ca4..efaf6337f7 100644 --- a/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py +++ b/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py @@ -29,20 +29,13 @@ code=Op.SSTORE(slot_code_worked, value_code_worked) + Op.RETURNCONTRACT[0](0, 0), max_stack_height=2, ) -stop_sub_container = Section.Container(container=Container(sections=[Section.Code(code=Op.STOP)])) -return_sub_container = Section.Container( - container=Container(sections=[Section.Code(code=Op.RETURN(0, 0), max_stack_height=2)]) -) -revert_sub_container = Section.Container( - container=Container(sections=[Section.Code(code=Op.REVERT(0, 0), max_stack_height=2)]) -) +stop_sub_container = Section.Container(Container.Code(Op.STOP)) +return_sub_container = Section.Container(Container.Code(Op.RETURN(0, 0))) +revert_sub_container = Section.Container(Container.Code(Op.REVERT(0, 0))) returncontract_sub_container = Section.Container( - container=Container( + Container( sections=[ - Section.Code( - code=Op.RETURNCONTRACT[0](0, 0), - max_stack_height=2, - ), + Section.Code(Op.RETURNCONTRACT[0](0, 0)), stop_sub_container, ], ) @@ -474,9 +467,9 @@ def test_container_both_kinds_different_sub(eof_test: EOFTestFiller): @pytest.mark.parametrize( ["deepest_container", "exception"], [ - pytest.param(Container(sections=[Section.Code(code=Op.STOP)]), None, id="valid"), + pytest.param(Container.Code(Op.STOP), None, id="valid"), pytest.param( - Container(sections=[Section.Code(code=Op.PUSH0)]), + Container.Code(code=Op.PUSH0), EOFException.MISSING_STOP_OPCODE, id="code-error", ), @@ -572,13 +565,71 @@ def test_wide_container(eof_test: EOFTestFiller, width: int, exception: EOFExcep + Op.POP + Op.STOP ), - Section.Container(Container(sections=[Section.Code(Op.INVALID)])), + Section.Container(Container.Code(Op.INVALID)), ], expected_bytecode=""" ef0001010004020001000b0300010014040000000080000436600060ff6000ec005000ef000101000402 000100010400000000800000fe""", ), - id="EOF1_eofcreate_valid_0", + id="eofcreate_0", + ), + pytest.param( + Container( + sections=[ + Section.Code(Op.PUSH1[0] + Op.RJUMP[0] + Op.STOP), + Section.Container(Container.Code(Op.INVALID)), + ], + expected_bytecode=""" + ef00010100040200010006030001001404000000008000016000e0000000ef0001010004020001000104 + 00000000800000fe""", + # Originally this test was "valid" because it was created + # before "orphan subcontainer" rule was introduced. + validity_error=EOFException.ORPHAN_SUBCONTAINER, + ), + id="orphan_subcontainer_0", + ), + pytest.param( + Container( + sections=[ + Section.Code(Op.PUSH1[0] + Op.RJUMP[0] + Op.STOP), + Section.Container(Container.Code(Op.INVALID)), + Section.Data(custom_size=2), + ], + expected_bytecode=""" + ef00010100040200010006030001001404000200008000016000e0000000ef0001010004020001000104 + 00000000800000fe""", + # Originally this test was "valid" but against the current spec + # it contains two errors: data section truncated and orphan subcontainer. + validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, + ), + id="orphan_subcontainer_0_and_truncated_data", + ), + pytest.param( + Container( + sections=[ + Section.Code(Op.PUSH1[0] + Op.RJUMP[0] + Op.STOP), + Section.Container(Container.Code(Op.INVALID)), + Section.Data("aabb"), + ], + expected_bytecode=""" + ef00010100040200010006030001001404000200008000016000e0000000ef0001010004020001000104 + 00000000800000feaabb""", + # Originally this test was "valid" because it was created + # before "orphan subcontainer" rule was introduced. + validity_error=EOFException.ORPHAN_SUBCONTAINER, + ), + id="orphan_subcontainer_0_and_data", + ), + pytest.param( + Container( + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section.Container("aabbccddeeff"), + ], + # The original test has been modified to reference the subcontainer by EOFCREATE. + validity_error=EOFException.INVALID_MAGIC, + ), + id="subcontainer_0_with_invalid_prefix", ), pytest.param( Container( @@ -593,7 +644,7 @@ def test_wide_container(eof_test: EOFTestFiller, width: int, exception: EOFExcep + Op.STOP ) ] - + 2 * [Section.Container(Container(sections=[Section.Code(Op.INVALID)]))], + + 2 * [Section.Container(Container.Code(Op.INVALID))], expected_bytecode=""" ef0001010004020001000b03000200140014040000000080000436600060ff6000ec015000ef00010100 0402000100010400000000800000feef000101000402000100010400000000800000fe""", @@ -601,7 +652,23 @@ def test_wide_container(eof_test: EOFTestFiller, width: int, exception: EOFExcep # before "orphan subcontainer" rule was introduced. validity_error=EOFException.ORPHAN_SUBCONTAINER, ), - id="EOF1_eofcreate_valid_1", + id="eofcreate_1_orphan_subcontainer_0", + ), + pytest.param( + Container( + sections=[ + Section.Code(Op.PUSH1[0] + Op.RJUMP[0] + Op.STOP), + Section.Container(Container.Code(Op.INVALID)), + Section.Container(Container.Code(Op.PUSH0 + Op.PUSH0 + Op.RETURN)), + ], + expected_bytecode=""" + ef000101000402000100060300020014001604000000008000016000e0000000ef000101000402000100 + 010400000000800000feef0001010004020001000304000000008000025f5ff3""", + # Originally this test was "valid" because it was created + # before "orphan subcontainer" rule was introduced. + validity_error=EOFException.ORPHAN_SUBCONTAINER, + ), + id="two_orphan_subcontainers", ), pytest.param( Container( @@ -616,12 +683,22 @@ def test_wide_container(eof_test: EOFTestFiller, width: int, exception: EOFExcep + Op.STOP ) ] - + 256 * [Section.Container(Container(sections=[Section.Code(Op.INVALID)]))], + + 256 * [Section.Container(Container.Code(Op.INVALID))], + # Originally this test was "valid" because it was created + # before "orphan subcontainer" rule was introduced. + validity_error=EOFException.ORPHAN_SUBCONTAINER, + ), + id="eofcreate_255_max_orphan_subcontainers", + ), + pytest.param( + Container( + sections=[Section.Code(Op.PUSH1[0] + Op.RJUMP[0] + Op.STOP)] + + 256 * [Section.Container(Container.Code(Op.INVALID))], # Originally this test was "valid" because it was created # before "orphan subcontainer" rule was introduced. validity_error=EOFException.ORPHAN_SUBCONTAINER, ), - id="EOF1_eofcreate_valid_2", + id="max_orphan_subcontainers", ), ], ) From d3d32190a63455bce810956a1f9b4f507b80364e Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Tue, 27 Aug 2024 21:11:07 +0200 Subject: [PATCH 03/17] new(tests): EIP-5656/7692 - use new marker to EOF-ize MCOPY test (#754) * new(tests): EIP-5656/7692 - use new marker to EOF-ize MCOPY test * new(tests): EIP-5656/7692 - EOFize remainder of MCOPY tests --- tests/cancun/eip5656_mcopy/test_mcopy.py | 2 + .../eip5656_mcopy/test_mcopy_contexts.py | 44 ++++------ .../test_mcopy_memory_expansion.py | 81 +++++++++---------- 3 files changed, 55 insertions(+), 72 deletions(-) diff --git a/tests/cancun/eip5656_mcopy/test_mcopy.py b/tests/cancun/eip5656_mcopy/test_mcopy.py index 53aaada64b..1e8ca50c19 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy.py @@ -175,6 +175,7 @@ def post(code_address: Address, code_storage: Storage) -> Mapping: # noqa: D103 "out_of_bounds_memory_extension", ], ) +@pytest.mark.with_all_evm_code_types @pytest.mark.valid_from("Cancun") def test_valid_mcopy_operations( state_test: StateTestFiller, @@ -202,6 +203,7 @@ def test_valid_mcopy_operations( @pytest.mark.parametrize("src", [0x00, 0x20]) @pytest.mark.parametrize("length", [0x00, 0x01]) @pytest.mark.parametrize("initial_memory", [bytes()], ids=["empty_memory"]) +@pytest.mark.with_all_evm_code_types @pytest.mark.valid_from("Cancun") def test_mcopy_on_empty_memory( state_test: StateTestFiller, diff --git a/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py b/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py index 26e0bf156a..47266f7348 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy_contexts.py @@ -26,7 +26,7 @@ def initial_memory_length() -> int: # noqa: D103 @pytest.fixture def callee_bytecode( initial_memory_length: int, - opcode: Op, + call_opcode: Op, ) -> Bytecode: """ Callee simply performs mcopy operations that should not have any effect on the @@ -44,7 +44,7 @@ def callee_bytecode( bytecode += Op.MCOPY(0x00, initial_memory_length * 2, 1) bytecode += Op.MCOPY(initial_memory_length * 2, 0x00, 1) - if opcode != Op.STATICCALL: + if call_opcode != Op.STATICCALL and call_opcode != Op.EXTSTATICCALL: # Simple sstore to make sure we actually ran the code bytecode += Op.SSTORE(200_000, 1) @@ -58,7 +58,7 @@ def callee_bytecode( def initial_memory( callee_bytecode: Bytecode, initial_memory_length: int, - opcode: Op, + call_opcode: Op, ) -> bytes: """ Initial memory for the test. @@ -67,7 +67,7 @@ def initial_memory( ret = bytes(list(islice(cycle(range(0x01, 0x100)), initial_memory_length))) - if opcode in [Op.CREATE, Op.CREATE2]: + if call_opcode in [Op.CREATE, Op.CREATE2]: # We also need to put the callee_bytecode as initcode in memory for create operations ret = bytes(callee_bytecode) + ret[len(callee_bytecode) :] @@ -85,7 +85,7 @@ def caller_bytecode( initial_memory: bytes, callee_address: Address, callee_bytecode: Bytecode, - opcode: Op, + call_opcode: Op, caller_storage: Storage, ) -> Bytecode: """ @@ -99,10 +99,10 @@ def caller_bytecode( bytecode += Op.MSTORE(i, Op.PUSH32(initial_memory[i : i + 0x20])) # Perform the call to the contract that is going to perform mcopy - if opcode in [Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL]: - bytecode += opcode(address=callee_address) - elif opcode in [Op.CREATE, Op.CREATE2]: - bytecode += opcode(size=len(callee_bytecode)) + if call_opcode in [Op.CREATE, Op.CREATE2]: + bytecode += call_opcode(size=len(callee_bytecode)) + else: + bytecode += call_opcode(address=callee_address) # First save msize bytecode += Op.SSTORE(100_000, Op.MSIZE()) @@ -141,12 +141,12 @@ def post( # noqa: D103 caller_address: Address, caller_storage: Storage, callee_address: Address, - opcode: Op, + call_opcode: Op, ) -> Mapping: callee_storage: Storage.StorageDictType = {} - if opcode in [Op.DELEGATECALL, Op.CALLCODE]: + if call_opcode in [Op.DELEGATECALL, Op.CALLCODE, Op.EXTDELEGATECALL]: caller_storage[200_000] = 1 - elif opcode in [Op.CALL]: + elif call_opcode in [Op.CALL, Op.EXTCALL]: callee_storage[200_000] = 1 return { caller_address: Account(storage=caller_storage), @@ -154,15 +154,7 @@ def post( # noqa: D103 } -@pytest.mark.parametrize( - "opcode", - [ - Op.CALL, - Op.DELEGATECALL, - Op.STATICCALL, - Op.CALLCODE, - ], -) +@pytest.mark.with_all_call_opcodes @pytest.mark.valid_from("Cancun") def test_no_memory_corruption_on_upper_call_stack_levels( state_test: StateTestFiller, @@ -172,13 +164,7 @@ def test_no_memory_corruption_on_upper_call_stack_levels( ): """ Perform a subcall with any of the following opcodes, which uses MCOPY during its execution, - and verify that the caller's memory is unaffected: - - `CALL` - - `CALLCODE` - - `DELEGATECALL` - - `STATICCALL` - - TODO: [EOF] Add EOF EXT*CALL opcodes + and verify that the caller's memory is unaffected """ state_test( env=Environment(), @@ -189,7 +175,7 @@ def test_no_memory_corruption_on_upper_call_stack_levels( @pytest.mark.parametrize( - "opcode", + "call_opcode", [ Op.CREATE, Op.CREATE2, diff --git a/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py b/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py index 88d3b32472..b17a44fda2 100644 --- a/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py +++ b/tests/cancun/eip5656_mcopy/test_mcopy_memory_expansion.py @@ -4,19 +4,29 @@ that produce a memory expansion, and potentially an out-of-gas error. """ # noqa: E501 -from typing import Mapping, Tuple +import itertools +from typing import Mapping import pytest from ethereum_test_tools import Account, Address, Alloc, Bytecode, Environment from ethereum_test_tools import Opcodes as Op -from ethereum_test_tools import StateTestFiller, Storage, Transaction, cost_memory_bytes +from ethereum_test_tools import StateTestFiller, Transaction, cost_memory_bytes +from ethereum_test_types.helpers import eip_2028_transaction_data_cost from .common import REFERENCE_SPEC_GIT_PATH, REFERENCE_SPEC_VERSION REFERENCE_SPEC_GIT_PATH = REFERENCE_SPEC_GIT_PATH REFERENCE_SPEC_VERSION = REFERENCE_SPEC_VERSION +"""Storage addresses for common testing fields""" +_slot = itertools.count(1) +slot_code_worked = next(_slot) +slot_last_slot = next(_slot) + +"""Storage values for common testing fields""" +value_code_worked = 0x2015 + @pytest.fixture def callee_bytecode(dest: int, src: int, length: int) -> Bytecode: @@ -31,6 +41,8 @@ def callee_bytecode(dest: int, src: int, length: int) -> Bytecode: # Pushes for the return operation bytecode += Op.PUSH1(0x00) + Op.PUSH1(0x00) + bytecode += Op.SSTORE(slot_code_worked, value_code_worked) + # Perform the mcopy operation bytecode += Op.MCOPY(dest, src, length) @@ -40,7 +52,7 @@ def callee_bytecode(dest: int, src: int, length: int) -> Bytecode: @pytest.fixture -def subcall_exact_cost( +def call_exact_cost( initial_memory: bytes, dest: int, length: int, @@ -48,6 +60,8 @@ def subcall_exact_cost( """ Returns the exact cost of the subcall, based on the initial memory and the length of the copy. """ + intrinsic_cost = 21000 + eip_2028_transaction_data_cost(initial_memory) + mcopy_cost = 3 mcopy_cost += 3 * ((length + 31) // 32) if length > 0 and dest + length > len(initial_memory): @@ -57,36 +71,18 @@ def subcall_exact_cost( calldatacopy_cost += 3 * ((len(initial_memory) + 31) // 32) calldatacopy_cost += cost_memory_bytes(len(initial_memory), 0) - pushes_cost = 3 * 7 + pushes_cost = 3 * 9 calldatasize_cost = 2 - return mcopy_cost + calldatacopy_cost + pushes_cost + calldatasize_cost - - -@pytest.fixture -def bytecode_storage( - subcall_exact_cost: int, - successful: bool, - memory_expansion_address: Address, -) -> Tuple[Bytecode, Storage.StorageDictType]: - """ - Prepares the bytecode and storage for the test, based on the expected result of the subcall - (whether it succeeds or fails depending on the length of the memory expansion). - """ - bytecode = Bytecode() - storage = {} - # Pass on the calldata - bytecode += Op.CALLDATACOPY(0x00, 0x00, Op.CALLDATASIZE()) - - subcall_gas = subcall_exact_cost if successful else subcall_exact_cost - 1 - - # Perform the subcall and store a one in the result location - bytecode += Op.SSTORE( - Op.CALL(subcall_gas, memory_expansion_address, 0, 0, Op.CALLDATASIZE(), 0, 0), 1 + sstore_cost = 22100 + return ( + intrinsic_cost + + mcopy_cost + + calldatacopy_cost + + pushes_cost + + calldatasize_cost + + sstore_cost ) - storage[int(successful)] = 1 - - return (bytecode, storage) @pytest.fixture @@ -101,10 +97,11 @@ def block_gas_limit() -> int: # noqa: D103 @pytest.fixture def tx_gas_limit( # noqa: D103 - subcall_exact_cost: int, + call_exact_cost: int, block_gas_limit: int, + successful: bool, ) -> int: - return min(max(500_000, subcall_exact_cost * 2), block_gas_limit) + return min(call_exact_cost - (0 if successful else 1), block_gas_limit) @pytest.fixture @@ -115,14 +112,7 @@ def env( # noqa: D103 @pytest.fixture -def caller_address( # noqa: D103 - pre: Alloc, bytecode_storage: Tuple[bytes, Storage.StorageDictType] -) -> Address: - return pre.deploy_contract(code=bytecode_storage[0]) - - -@pytest.fixture -def memory_expansion_address(pre: Alloc, callee_bytecode: Bytecode) -> Address: # noqa: D103 +def caller_address(pre: Alloc, callee_bytecode: bytes) -> Address: # noqa: D103 return pre.deploy_contract(code=callee_bytecode) @@ -151,10 +141,13 @@ def tx( # noqa: D103 @pytest.fixture def post( # noqa: D103 - caller_address: Address, bytecode_storage: Tuple[bytes, Storage.StorageDictType] + caller_address: Address, + successful: bool, ) -> Mapping: return { - caller_address: Account(storage=bytecode_storage[1]), + caller_address: Account( + storage={slot_code_worked: value_code_worked} if successful else {} + ) } @@ -197,6 +190,7 @@ def post( # noqa: D103 "from_empty_memory", ], ) +@pytest.mark.with_all_evm_code_types @pytest.mark.valid_from("Cancun") def test_mcopy_memory_expansion( state_test: StateTestFiller, @@ -242,7 +236,7 @@ def test_mcopy_memory_expansion( ], ) @pytest.mark.parametrize( - "subcall_exact_cost", + "call_exact_cost", [2**128 - 1], ids=[""], ) # Limit subcall gas, otherwise it would be impossibly large @@ -258,6 +252,7 @@ def test_mcopy_memory_expansion( "from_empty_memory", ], ) +@pytest.mark.with_all_evm_code_types @pytest.mark.valid_from("Cancun") def test_mcopy_huge_memory_expansion( state_test: StateTestFiller, From 810f2d47a841dea6746c143a6217601287f55b2b Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 21 Aug 2024 14:27:46 -0600 Subject: [PATCH 04/17] Fuzzing related findings A collection of fuzzing related updates to the test * Activate functions validation tests, and move to 4750 dir * Add terminal opcode to some tests so they have only one error * Tests found via fuzzing coverage * subcontainer wrong size * subcontainer wrong eof version * EOFCREATE nonexistant container * Many CALLF test covered by inactive 4750 checks Signed-off-by: Danno Ferrin --- .../code_validation_function.py | 189 ------------------ .../eip3540_eof_v1/test_code_validation.py | 101 +--------- .../eip4200_relative_jumps/test_rjump.py | 46 +++++ .../eip4750_functions/test_code_validation.py | 161 +++++++++++++++ .../eip7620_eof_create/test_eofcreate.py | 21 ++ .../test_subcontainer_validation.py | 49 +++++ 6 files changed, 282 insertions(+), 285 deletions(-) delete mode 100644 tests/prague/eip7692_eof_v1/eip3540_eof_v1/code_validation_function.py create mode 100644 tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/code_validation_function.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/code_validation_function.py deleted file mode 100644 index b8026563ed..0000000000 --- a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/code_validation_function.py +++ /dev/null @@ -1,189 +0,0 @@ -""" -Code validation of CALLF, RETF opcodes tests -""" - -from typing import List - -from ethereum_test_tools.eof.v1 import Container, Section -from ethereum_test_tools.eof.v1.constants import MAX_CODE_SECTIONS -from ethereum_test_tools.vm.opcode import Opcodes as Op - -VALID: List[Container] = [ - Container( - name="retf_code_input_output", - sections=[ - Section.Code( - code=Op.PUSH0 + Op.CALLF[1] + Op.POP + Op.POP + Op.STOP, - code_inputs=0, - code_outputs=0, - max_stack_height=2, - ), - Section.Code( - code=Op.PUSH0 + Op.RETF, - code_inputs=1, - code_outputs=2, - max_stack_height=2, - ), - ], - ), - Container( - name="stack_height_equal_code_outputs_retf_zero_stop", - sections=[ - Section.Code( - code=Op.CALLF[1] + Op.POP + Op.STOP, - code_inputs=0, - code_outputs=0, - max_stack_height=1, - ), - Section.Code( - code=( - Op.RJUMPI[len(Op.PUSH0) + len(Op.RETF)](Op.ORIGIN) - + Op.PUSH0 - + Op.RETF - + Op.STOP - ), - code_inputs=0, - code_outputs=1, - max_stack_height=1, - ), - ], - ), - Container( - name="callf_max_code_sections_1", - sections=[ - Section.Code( - code=(sum(Op.CALLF[i] for i in range(1, MAX_CODE_SECTIONS)) + Op.STOP), - code_inputs=0, - code_outputs=0, - max_stack_height=0, - ) - ] - + ( - [ - Section.Code( - code=Op.RETF, - code_inputs=0, - code_outputs=0, - max_stack_height=0, - ) - ] - * (MAX_CODE_SECTIONS - 1) - ), - ), - Container( - name="callf_max_code_sections_2", - sections=[ - Section.Code( - code=(Op.CALLF[i + 1] + Op.RETF), - code_inputs=0, - code_outputs=0, - max_stack_height=0, - ) - for i in range(MAX_CODE_SECTIONS - 1) - ] - + [ - Section.Code( - code=Op.RETF, - code_inputs=0, - code_outputs=0, - max_stack_height=0, - ) - ], - ), -] - -INVALID: List[Container] = [ - Container( - name="function_underflow", - sections=[ - Section.Code( - code=(Op.PUSH0 + Op.CALLF[1] + Op.STOP), - code_inputs=0, - code_outputs=0, - max_stack_height=2, - ), - Section.Code( - code=(Op.POP + Op.POP + Op.RETF), - code_inputs=1, - code_outputs=0, - max_stack_height=2, - ), - ], - validity_error="StackUnderflow", - ), - Container( - name="stack_higher_than_code_outputs", - sections=[ - Section.Code( - code=(Op.STOP), - code_inputs=0, - code_outputs=0, - max_stack_height=0, - ), - Section.Code( - code=(Op.PUSH0 + Op.RETF), - code_inputs=0, - code_outputs=0, - max_stack_height=1, - ), - ], - validity_error="InvalidRetf", - ), - Container( - name="stack_shorter_than_code_outputs", - sections=[ - Section.Code( - code=(Op.STOP), - code_inputs=0, - code_outputs=0, - max_stack_height=0, - ), - Section.Code( - code=(Op.PUSH0 + Op.RETF), - code_inputs=0, - code_outputs=2, - max_stack_height=1, - ), - ], - validity_error="InvalidRetf", - ), - Container( - name="oob_callf_1", - sections=[ - Section.Code( - code=(Op.PUSH0 + Op.CALLF[2] + Op.STOP), - code_inputs=0, - code_outputs=0, - max_stack_height=1, - ), - Section.Code( - code=(Op.POP + Op.POP + Op.RETF), - code_inputs=1, - code_outputs=0, - max_stack_height=2, - ), - ], - validity_error="StackUnderflow", - ), - Container( - name="overflow_code_sections_1", - sections=[ - Section.Code( - code=(Op.CALLF[i + 1] + Op.RETF), - code_inputs=0, - code_outputs=0, - max_stack_height=0, - ) - for i in range(MAX_CODE_SECTIONS) - ] - + [ - Section.Code( - code=Op.RETF, - code_inputs=0, - code_outputs=0, - max_stack_height=0, - ) - ], - validity_error="InvalidTypeSize", - ), -] diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py index 127dd46985..3af9e07cc9 100644 --- a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py +++ b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py @@ -2,41 +2,13 @@ EOF V1 Code Validation tests """ -from typing import Dict, List - import pytest -from ethereum_test_tools import ( - EOA, - Account, - Address, - Alloc, - Environment, - EOFTestFiller, - Transaction, - compute_eofcreate_address, -) -from ethereum_test_tools.eof.v1 import Container, Initcode +from ethereum_test_tools import EOFTestFiller +from ethereum_test_tools.eof.v1 import Container from .. import EOF_FORK_NAME - -# from .code_validation import INVALID as INVALID_CODE -# from .code_validation import VALID as VALID_CODE -# from .code_validation_function import INVALID as INVALID_FN -# from .code_validation_function import VALID as VALID_FN -# from .code_validation_jump import INVALID as INVALID_RJUMP -# from .code_validation_jump import VALID as VALID_RJUMP -from .container import INVALID as INVALID_CONTAINERS -from .container import VALID as VALID_CONTAINERS - -# from .tests_execution_function import VALID as VALID_EXEC_FN - -ALL_VALID = VALID_CONTAINERS -ALL_INVALID = INVALID_CONTAINERS -# ALL_VALID = ( -# VALID_CONTAINERS + VALID_CODE + VALID_RJUMP + VALID_FN + VALID_EXEC_FN -# ) -# ALL_INVALID = INVALID_CONTAINERS + INVALID_CODE + INVALID_RJUMP + INVALID_FN +from .container import INVALID, VALID REFERENCE_SPEC_GIT_PATH = "EIPS/eip-3540.md" REFERENCE_SPEC_VERSION = "8dcb0a8c1c0102c87224308028632cc986a61183" @@ -44,69 +16,6 @@ pytestmark = pytest.mark.valid_from(EOF_FORK_NAME) -@pytest.fixture -def env(): # noqa: D103 - return Environment() - - -@pytest.fixture -def sender(pre: Alloc): # noqa: D103 - return pre.fund_eoa() - - -@pytest.fixture -def create3_init_container(container: Container) -> Initcode: # noqa: D103 - return Initcode(deploy_container=container) - - -@pytest.fixture -def create3_opcode_contract_address( # noqa: D103 - pre: Alloc, - create3_init_container: Initcode, -) -> Address: - return pre.deploy_contract(create3_init_container, address=Address(0x300)) - - -@pytest.fixture -def txs( # noqa: D103 - sender: EOA, - create3_opcode_contract_address: Address, -) -> List[Transaction]: - return [ - Transaction( - to=create3_opcode_contract_address, - gas_limit=100000000, - gas_price=10, - # data=initcode, - protected=False, - sender=sender, - ) - ] - - -@pytest.fixture -def post( # noqa: D103 - create3_init_container: Initcode, - container: Container, - create3_opcode_contract_address: Address, -) -> Dict[Address, Account]: - create_opcode_created_contract_address = compute_eofcreate_address( - create3_opcode_contract_address, - 0, - bytes(create3_init_container.init_container), - ) - - new_account = Account(code=container) - - # Do not expect to create account if it is invalid - if hasattr(new_account, "code") and container.validity_error != "": - return {} - else: - return { - create_opcode_created_contract_address: new_account, - } - - def container_name(c: Container): """ Return the name of the container for use in pytest ids. @@ -119,7 +28,7 @@ def container_name(c: Container): @pytest.mark.parametrize( "container", - ALL_VALID, + VALID, ids=container_name, ) def test_legacy_initcode_valid_eof_v1_contract( @@ -140,7 +49,7 @@ def test_legacy_initcode_valid_eof_v1_contract( @pytest.mark.parametrize( "container", - ALL_INVALID, + INVALID, ids=container_name, ) def test_legacy_initcode_invalid_eof_v1_contract( diff --git a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py index 7b2fe247b9..76210ec841 100644 --- a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py +++ b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py @@ -696,3 +696,49 @@ def test_rjump_backwards_reference_only( data=container, expect_exception=EOFException.UNREACHABLE_INSTRUCTIONS, ) + + +def test_rjump_backwards_illegal_stack_height( + eof_test: EOFTestFiller, +): + """ + Invalid backward jump, found via fuzzing coverage + """ + eof_test( + data=Container.Code( + code=( + Op.PUSH0 + + Op.RJUMPI[3] + + Op.RJUMP(7) + + Op.PUSH2(0x2015) + + Op.PUSH3(0x015500) + + Op.RJUMP[-10] + ), + max_stack_height=0x24, + ), + expect_exception=EOFException.STACK_HEIGHT_MISMATCH, + ) + + +def test_rjump_backwards_infinite_loop( + eof_test: EOFTestFiller, +): + """ + Infinite loop code containing RJUMP immediate + """ + eof_test( + data=Container( + name="infinite_loop", + sections=[ + Section.Code( + code=Op.PUSH0 + + Op.RJUMPI[3] + + Op.RJUMP[7] + + Op.SSTORE(1, 0x2015) + + Op.STOP + + Op.RJUMP[-10] + ), + Section.Data(data="0xdeadbeef"), + ], + ), + ) diff --git a/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py b/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py new file mode 100644 index 0000000000..c6298f31b1 --- /dev/null +++ b/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py @@ -0,0 +1,161 @@ +""" +Code validation of CALLF, RETF opcodes tests +""" + +from typing import List + +import pytest + +from ethereum_test_tools import EOFException, EOFTestFiller +from ethereum_test_tools.eof.v1 import Container, Section +from ethereum_test_tools.eof.v1.constants import MAX_CODE_SECTIONS +from ethereum_test_tools.vm.opcode import Opcodes as Op + +VALID: List[Container] = [ + Container( + name="retf_code_input_output", + sections=[ + Section.Code(code=Op.PUSH0 + Op.CALLF[1] + Op.POP + Op.POP + Op.STOP), + Section.Code( + code=Op.PUSH0 + Op.RETF, + code_outputs=1, + ), + ], + ), + Container( + name="callf_max_code_sections_1", + sections=[ + Section.Code(code=(sum(Op.CALLF[i] for i in range(1, MAX_CODE_SECTIONS)) + Op.STOP)) + ] + + ( + [ + Section.Code( + code=Op.RETF, + code_outputs=0, + ) + ] + * (MAX_CODE_SECTIONS - 1) + ), + ), + Container( + name="callf_max_code_sections_2", + sections=[Section.Code(code=(Op.CALLF[1] + Op.STOP))] + + [ + Section.Code( + code=(Op.CALLF[i + 2] + Op.RETF), + code_outputs=0, + ) + for i in range(MAX_CODE_SECTIONS - 2) + ] + + [ + Section.Code( + code=Op.RETF, + code_outputs=0, + ) + ], + ), +] + +INVALID: List[Container] = [ + Container( + name="function_underflow", + sections=[ + Section.Code(code=(Op.PUSH0 + Op.CALLF[1] + Op.STOP)), + Section.Code( + code=(Op.POP + Op.POP + Op.RETF), + code_inputs=1, + code_outputs=0, + ), + ], + validity_error=EOFException.STACK_UNDERFLOW, + ), + Container( + name="stack_higher_than_code_outputs", + sections=[ + Section.Code( + code=(Op.CALLF[1] + Op.STOP), + ), + Section.Code( + code=(Op.PUSH0 + Op.RETF), + code_outputs=0, + ), + ], + validity_error=EOFException.STACK_HIGHER_THAN_OUTPUTS, + ), + Container( + name="stack_shorter_than_code_outputs", + sections=[ + Section.Code( + code=(Op.CALLF[1] + Op.STOP), + ), + Section.Code( + code=(Op.PUSH0 + Op.RETF), + code_outputs=2, + max_stack_height=1, + ), + ], + validity_error=EOFException.INVALID_MAX_STACK_HEIGHT, + ), + Container( + name="oob_callf_1", + sections=[ + Section.Code( + code=(Op.CALLF[2] + Op.STOP), + ), + Section.Code( + code=(Op.RETF), + code_outputs=0, + ), + ], + validity_error=EOFException.INVALID_CODE_SECTION_INDEX, + ), + Container( + name="overflow_code_sections_1", + sections=[ + Section.Code( + code=(Op.CALLF[1] + Op.STOP), + ) + ] + + [ + Section.Code( + code=(Op.CALLF[i + 2] + Op.RETF), + code_outputs=0, + ) + for i in range(MAX_CODE_SECTIONS) + ] + + [ + Section.Code( + code=Op.RETF, + code_outputs=0, + ) + ], + validity_error=EOFException.TOO_MANY_CODE_SECTIONS, + ), +] + + +def container_name(c: Container): + """ + Return the name of the container for use in pytest ids. + """ + if hasattr(c, "name"): + return c.name + else: + return c.__class__.__name__ + + +@pytest.mark.parametrize( + "container", + [*VALID, *INVALID], + ids=container_name, +) +def test_eof_validity( + eof_test: EOFTestFiller, + container: Container, +): + """ + Test EOF container validaiton for features around EIP-4750 / Functions / Code Sections + """ + eof_test( + data=bytes(container), + ) diff --git a/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py b/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py index 0bb9ae237f..ba67774519 100644 --- a/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py +++ b/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_eofcreate.py @@ -4,6 +4,8 @@ import pytest +from ethereum_test_exceptions import EOFException +from ethereum_test_specs import EOFTestFiller from ethereum_test_tools import ( Account, Alloc, @@ -569,3 +571,22 @@ def test_eofcreate_revert_eof_returndata( ) state_test(env=env, pre=pre, post=post, tx=tx) + + +@pytest.mark.parametrize("index", [1, 255], ids=lambda x: x) +def test_eofcreate_invalid_index( + eof_test: EOFTestFiller, + index: int, +): + """Referring to non-existent container section index""" + eof_test( + data=Container( + sections=[ + Section.Code( + code=Op.EOFCREATE[index](0, 0, 0, 0) + Op.STOP, + ), + Section.Container(container=Container(sections=[Section.Code(code=Op.INVALID)])), + ], + ), + expect_exception=EOFException.INVALID_CONTAINER_SECTION_INDEX, + ) diff --git a/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py b/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py index 1b5e586ca4..6170fe5133 100644 --- a/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py +++ b/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py @@ -471,6 +471,55 @@ def test_container_both_kinds_different_sub(eof_test: EOFTestFiller): ) +@pytest.mark.parametrize("version", [0, 255], ids=lambda x: x) +def test_subcontainer_wrong_eof_version( + eof_test: EOFTestFiller, + version: int, +): + """Test multiple kinds of subcontainer at the same level""" + eof_test( + data=Container( + sections=[ + Section.Code( + code=Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP, + ), + Section.Container( + container=Container(version=[version], sections=[Section.Code(code=Op.STOP)]) + ), + ], + kind=ContainerKind.RUNTIME, + ), + expect_exception=EOFException.INVALID_VERSION, + ) + + +@pytest.mark.parametrize("delta", [-1, 1], ids=["smaller", "larger"]) +@pytest.mark.parametrize("kind", [ContainerKind.RUNTIME, ContainerKind.INITCODE]) +def test_subcontainer_wrong_size( + eof_test: EOFTestFiller, + delta: int, + kind: ContainerKind, +): + """Test multiple kinds of subcontainer at the same level""" + eof_test( + data=Container( + sections=[ + Section.Code( + code=(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP) + if kind == ContainerKind.RUNTIME + else (Op.RETURNCONTRACT[0](0, 0)), + ), + Section.Container( + container=Container(sections=[Section.Code(code=Op.STOP)]), + custom_size=len(stop_sub_container.data) + delta, + ), + ], + kind=kind, + ), + expect_exception=EOFException.INVALID_SECTION_BODIES_SIZE, + ) + + @pytest.mark.parametrize( ["deepest_container", "exception"], [ From b5622fd04686816b3ad1bd6ce8aa2babe8db810a Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 21 Aug 2024 15:02:07 -0600 Subject: [PATCH 05/17] tox Signed-off-by: Danno Ferrin --- .../eip4750_functions/test_code_validation.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py b/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py index c6298f31b1..b8b8eccce9 100644 --- a/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py +++ b/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py @@ -11,6 +11,13 @@ from ethereum_test_tools.eof.v1.constants import MAX_CODE_SECTIONS from ethereum_test_tools.vm.opcode import Opcodes as Op +from .. import EOF_FORK_NAME + +REFERENCE_SPEC_GIT_PATH = "EIPS/eip-4750.md" +REFERENCE_SPEC_VERSION = "14400434e1199c57d912082127b1d22643788d11" + +pytestmark = pytest.mark.valid_from(EOF_FORK_NAME) + VALID: List[Container] = [ Container( name="retf_code_input_output", From 47c5b7295be836f3d800353f30297ca360d4b2da Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 21 Aug 2024 18:15:30 -0600 Subject: [PATCH 06/17] review comments Signed-off-by: Danno Ferrin --- .../eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py | 4 ++-- .../eip7620_eof_create/test_subcontainer_validation.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py index 76210ec841..230df16879 100644 --- a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py +++ b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py @@ -724,11 +724,11 @@ def test_rjump_backwards_infinite_loop( eof_test: EOFTestFiller, ): """ - Infinite loop code containing RJUMP immediate + Validate that a backwards RJUMP as terminal operation is valid """ eof_test( data=Container( - name="infinite_loop", + name="backwards_rjump_terminal", sections=[ Section.Code( code=Op.PUSH0 diff --git a/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py b/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py index 6170fe5133..704854b75c 100644 --- a/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py +++ b/tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py @@ -476,7 +476,7 @@ def test_subcontainer_wrong_eof_version( eof_test: EOFTestFiller, version: int, ): - """Test multiple kinds of subcontainer at the same level""" + """Test a subcontainer with the incorrect EOF version""" eof_test( data=Container( sections=[ @@ -500,7 +500,7 @@ def test_subcontainer_wrong_size( delta: int, kind: ContainerKind, ): - """Test multiple kinds of subcontainer at the same level""" + """Test a subcontainer with the incorrect size in the parent's header""" eof_test( data=Container( sections=[ From bef3885bd2d5a0a75cf2db4e74efb1fecc6d0c7b Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 27 Aug 2024 16:58:11 -0600 Subject: [PATCH 07/17] more fuzz fixes Signed-off-by: Danno Ferrin --- .../eip4200_relative_jumps/test_rjumpi.py | 41 +++++++++++++++++++ .../eip4200_relative_jumps/test_rjumpv.py | 17 +++++++- .../eip4750_functions/test_code_validation.py | 35 ++++++++++++++++ .../eip663_dupn_swapn_exchange/test_swapn.py | 3 +- 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py index 10cfa17521..4a440ff2eb 100644 --- a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py +++ b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py @@ -827,3 +827,44 @@ def test_rjumpi_backwards_reference_only( data=container, expect_exception=EOFException.UNREACHABLE_INSTRUCTIONS, ) + + +def test_tangled_rjumpi( + eof_test: EOFTestFiller, +): + """ + EOF code containing tangled RJUMPI paths + """ + container = Container.Code( + code=( + Op.PUSH0 # [0,0] + + Op.PUSH0 # [1,1] + + Op.RJUMPI[8] # [2,2] + + Op.PUSH1(127) # [1,1] + + Op.RJUMPI[7] # [2,2] + + Op.RJUMP[5] # [1,1] + + Op.PUSH0 # [1,1] + + Op.RJUMP[0] # [2,1] + + Op.LT # [1,x] + + Op.STOP # [1,x] + ) + ) + eof_test( + data=container, + expect_exception=EOFException.STACK_UNDERFLOW, + ) + + +def test_rjumpi_backwards_onto_dup( + eof_test: EOFTestFiller, +): + """ + Backwards jumpi onto a dup + """ + container = Container.Code( + code=(Op.PUSH0 + Op.DUP1 + Op.RJUMPI[-4] + Op.STOP), + max_stack_height=2, + ) + eof_test( + data=container, + ) diff --git a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py index 286360610b..38b373d1bf 100644 --- a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py +++ b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py @@ -122,6 +122,21 @@ def test_rjumpv_backwards( ) +def test_rjumpv_backwards_onto_dup( + eof_test: EOFTestFiller, +): + """ + Backwards jump vector onto a dup + """ + container = Container.Code( + code=(Op.PUSH0 + Op.DUP1 + Op.RJUMPV[-5] + Op.STOP), + max_stack_height=2, + ) + eof_test( + data=container, + ) + + def test_rjumpv_zero( eof_state_test: EOFStateTestFiller, ): @@ -982,7 +997,7 @@ def test_rjumpv_into_swapn( pytest.param(256, 255, id="t256i255"), ], ) -def test_rjump_into_exchange( +def test_rjumpv_into_exchange( eof_test: EOFTestFiller, table_size: int, invalid_index: int, diff --git a/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py b/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py index b8b8eccce9..ada93e8d33 100644 --- a/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py +++ b/tests/prague/eip7692_eof_v1/eip4750_functions/test_code_validation.py @@ -29,6 +29,27 @@ ), ], ), + Container( + name="stack_height_equal_code_outputs_retf_zero_stop", + sections=[ + Section.Code( + code=Op.CALLF[1] + Op.POP + Op.STOP, + code_inputs=0, + max_stack_height=1, + ), + Section.Code( + code=( + Op.RJUMPI[len(Op.PUSH0) + len(Op.RETF)](Op.ORIGIN) + + Op.PUSH0 + + Op.RETF + + Op.STOP + ), + code_inputs=0, + code_outputs=1, + max_stack_height=1, + ), + ], + ), Container( name="callf_max_code_sections_1", sections=[ @@ -138,6 +159,19 @@ ], validity_error=EOFException.TOO_MANY_CODE_SECTIONS, ), + Container( + name="callf_to_non_returning", + sections=[ + Section.Code( + code=(Op.CALLF[1] + Op.STOP), + ), + Section.Code( + code=(Op.STOP), + code_outputs=0, + ), + ], + validity_error=EOFException.INVALID_NON_RETURNING_FLAG, + ), ] @@ -165,4 +199,5 @@ def test_eof_validity( """ eof_test( data=bytes(container), + expect_exception=container.validity_error, ) diff --git a/tests/prague/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py b/tests/prague/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py index d2c8c48f32..63f9e39618 100644 --- a/tests/prague/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py +++ b/tests/prague/eip7692_eof_v1/eip663_dupn_swapn_exchange/test_swapn.py @@ -79,6 +79,7 @@ def test_swapn_on_max_stack( [ 0, 1, + 21, 2**8 - 1, ], ) @@ -96,7 +97,7 @@ def test_swapn_stack_underflow( code=sum(Op.PUSH2[v] for v in range(0, stack_height)) + Op.SWAPN[stack_height] + Op.STOP, - max_stack_height=MAX_OPERAND_STACK_HEIGHT, + max_stack_height=stack_height, ) ], ) From ad16fbfcbf494fdebf9d09893f2f40c515af440b Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Tue, 27 Aug 2024 18:01:57 -0600 Subject: [PATCH 08/17] large table backwards rjumpv Signed-off-by: Danno Ferrin --- .../eip4200_relative_jumps/test_rjumpv.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py index 38b373d1bf..6f4fda1a7d 100644 --- a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py +++ b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py @@ -137,6 +137,25 @@ def test_rjumpv_backwards_onto_dup( ) +@pytest.mark.parametrize("len", [8, 9]) +def test_rjumpv_backwards_large_table( + eof_test: EOFTestFiller, + len: int, +): + """ + Backwards jump vector with a large table + """ + jump_table = [0] * len + jump_table += [len * -2 - 6] + container = Container.Code( + code=(Op.RJUMPV[jump_table](len) + Op.STOP), + max_stack_height=1, + ) + eof_test( + data=container, + ) + + def test_rjumpv_zero( eof_state_test: EOFStateTestFiller, ): From 4ae1d3246a2c21af08ef9b751648b95c9edb1de0 Mon Sep 17 00:00:00 2001 From: winsvega Date: Wed, 28 Aug 2024 14:07:50 +0300 Subject: [PATCH 09/17] feat(tests): test all opcodes by fork (#748) Co-authored-by: danceratopz --- converted-ethereum-tests.txt | 4 + docs/CHANGELOG.md | 2 + src/ethereum_test_forks/base_fork.py | 10 + src/ethereum_test_forks/forks/forks.py | 214 +++++++++++++++++++++ src/ethereum_test_tools/tests/test_code.py | 12 ++ tests/frontier/opcodes/test_all_opcodes.py | 108 +++++++++++ 6 files changed, 350 insertions(+) create mode 100644 tests/frontier/opcodes/test_all_opcodes.py diff --git a/converted-ethereum-tests.txt b/converted-ethereum-tests.txt index e49231997d..f11bdc4490 100644 --- a/converted-ethereum-tests.txt +++ b/converted-ethereum-tests.txt @@ -1,3 +1,7 @@ +([#748](https://github.com/ethereum/execution-spec-tests/pull/748)) +GeneralStateTests/stBadOpcode/badOpcodes.json +GeneralStateTests/stBugs/evmBytecode.json + ([#497](https://github.com/ethereum/execution-spec-tests/pull/497)) GeneralStateTests/stCreate2/call_outsize_then_create2_successful_then_returndatasize.json GeneralStateTests/stCreate2/call_then_create2_successful_then_returndatasize.json diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 780ea4b45d..2cdcf4f31f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,7 @@ Test fixtures for use by clients are available for each release on the [Github r - ✨ EIP-4844 test `tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py` includes an EOF test case ([#610](https://github.com/ethereum/execution-spec-tests/pull/610)). - ✨ Example test `tests/frontier/opcodes/test_dup.py` now includes EOF parametrization ([#610](https://github.com/ethereum/execution-spec-tests/pull/610)). +- ✨ Convert all opcodes validation test `tests/frontier/opcodes/test_all_opcodes.py` ([#748](https://github.com/ethereum/execution-spec-tests/pull/748)). ### 🛠️ Framework @@ -29,6 +30,7 @@ Test fixtures for use by clients are available for each release on the [Github r - ✨ Added optional parameter to all `with_all_*` markers to specify a lambda function that filters the parametrized values ([#739](https://github.com/ethereum/execution-spec-tests/pull/739)). - ✨ Added [`extend_with_defaults` utility function](https://ethereum.github.io/execution-spec-tests/main/writing_tests/writing_a_new_test/#ethereum_test_tools.utility.pytest.extend_with_defaults), which helps extend test case parameter sets with default values. `@pytest.mark.parametrize` ([#739](https://github.com/ethereum/execution-spec-tests/pull/739)). - ✨ Added `Container.Init` to `ethereum_test_types.EOF.V1` package, which allows generation of an EOF init container more easily ([#739](https://github.com/ethereum/execution-spec-tests/pull/739)). +- ✨ Introduce method valid_opcodes() to the fork class ([#748](https://github.com/ethereum/execution-spec-tests/pull/748)). - 🐞 Fixed `consume` exit code return values, ensuring that pytest's return value is correctly propagated to the shell. This allows the shell to accurately reflect the test results (e.g., failures) based on the pytest exit code ([#765](https://github.com/ethereum/execution-spec-tests/pull/765)). ### 🔧 EVM Tools diff --git a/src/ethereum_test_forks/base_fork.py b/src/ethereum_test_forks/base_fork.py index 7c4e01ac1d..ef1d525309 100644 --- a/src/ethereum_test_forks/base_fork.py +++ b/src/ethereum_test_forks/base_fork.py @@ -289,6 +289,16 @@ def call_opcodes( """ pass + @classmethod + @abstractmethod + def valid_opcodes( + cls, + ) -> List[Opcodes]: + """ + Returns the list of Opcodes that are valid to work on this fork. + """ + pass + @classmethod @abstractmethod def create_opcodes( diff --git a/src/ethereum_test_forks/forks/forks.py b/src/ethereum_test_forks/forks/forks.py index 081c455fe2..f56426c78f 100644 --- a/src/ethereum_test_forks/forks/forks.py +++ b/src/ethereum_test_forks/forks/forks.py @@ -199,6 +199,145 @@ def call_opcodes( (Opcodes.CALLCODE, EVMCodeType.LEGACY), ] + @classmethod + def valid_opcodes( + cls, + ) -> List[Opcodes]: + """ + Returns the list of Opcodes that are valid to work on this fork. + """ + return [ + Opcodes.STOP, + Opcodes.ADD, + Opcodes.MUL, + Opcodes.SUB, + Opcodes.DIV, + Opcodes.SDIV, + Opcodes.MOD, + Opcodes.SMOD, + Opcodes.ADDMOD, + Opcodes.MULMOD, + Opcodes.EXP, + Opcodes.SIGNEXTEND, + Opcodes.LT, + Opcodes.GT, + Opcodes.SLT, + Opcodes.SGT, + Opcodes.EQ, + Opcodes.ISZERO, + Opcodes.AND, + Opcodes.OR, + Opcodes.XOR, + Opcodes.NOT, + Opcodes.BYTE, + Opcodes.SHA3, + Opcodes.ADDRESS, + Opcodes.BALANCE, + Opcodes.ORIGIN, + Opcodes.CALLER, + Opcodes.CALLVALUE, + Opcodes.CALLDATALOAD, + Opcodes.CALLDATASIZE, + Opcodes.CALLDATACOPY, + Opcodes.CODESIZE, + Opcodes.CODECOPY, + Opcodes.GASPRICE, + Opcodes.EXTCODESIZE, + Opcodes.EXTCODECOPY, + Opcodes.BLOCKHASH, + Opcodes.COINBASE, + Opcodes.TIMESTAMP, + Opcodes.NUMBER, + Opcodes.PREVRANDAO, + Opcodes.GASLIMIT, + Opcodes.POP, + Opcodes.MLOAD, + Opcodes.MSTORE, + Opcodes.MSTORE8, + Opcodes.SLOAD, + Opcodes.SSTORE, + Opcodes.PC, + Opcodes.MSIZE, + Opcodes.GAS, + Opcodes.JUMP, + Opcodes.JUMPI, + Opcodes.JUMPDEST, + Opcodes.PUSH1, + Opcodes.PUSH2, + Opcodes.PUSH3, + Opcodes.PUSH4, + Opcodes.PUSH5, + Opcodes.PUSH6, + Opcodes.PUSH7, + Opcodes.PUSH8, + Opcodes.PUSH9, + Opcodes.PUSH10, + Opcodes.PUSH11, + Opcodes.PUSH12, + Opcodes.PUSH13, + Opcodes.PUSH14, + Opcodes.PUSH15, + Opcodes.PUSH16, + Opcodes.PUSH17, + Opcodes.PUSH18, + Opcodes.PUSH19, + Opcodes.PUSH20, + Opcodes.PUSH21, + Opcodes.PUSH22, + Opcodes.PUSH23, + Opcodes.PUSH24, + Opcodes.PUSH25, + Opcodes.PUSH26, + Opcodes.PUSH27, + Opcodes.PUSH28, + Opcodes.PUSH29, + Opcodes.PUSH30, + Opcodes.PUSH31, + Opcodes.PUSH32, + Opcodes.DUP1, + Opcodes.DUP2, + Opcodes.DUP3, + Opcodes.DUP4, + Opcodes.DUP5, + Opcodes.DUP6, + Opcodes.DUP7, + Opcodes.DUP8, + Opcodes.DUP9, + Opcodes.DUP10, + Opcodes.DUP11, + Opcodes.DUP12, + Opcodes.DUP13, + Opcodes.DUP14, + Opcodes.DUP15, + Opcodes.DUP16, + Opcodes.SWAP1, + Opcodes.SWAP2, + Opcodes.SWAP3, + Opcodes.SWAP4, + Opcodes.SWAP5, + Opcodes.SWAP6, + Opcodes.SWAP7, + Opcodes.SWAP8, + Opcodes.SWAP9, + Opcodes.SWAP10, + Opcodes.SWAP11, + Opcodes.SWAP12, + Opcodes.SWAP13, + Opcodes.SWAP14, + Opcodes.SWAP15, + Opcodes.SWAP16, + Opcodes.LOG0, + Opcodes.LOG1, + Opcodes.LOG2, + Opcodes.LOG3, + Opcodes.LOG4, + Opcodes.CREATE, + Opcodes.CALL, + Opcodes.CALLCODE, + Opcodes.RETURN, + Opcodes.SELFDESTRUCT, + ] + @classmethod def create_opcodes( cls, block_number: int = 0, timestamp: int = 0 @@ -254,6 +393,15 @@ def call_opcodes( Homestead, cls ).call_opcodes(block_number, timestamp) + @classmethod + def valid_opcodes( + cls, + ) -> List[Opcodes]: + """ + Returns the list of Opcodes that are valid to work on this fork. + """ + return [Opcodes.DELEGATECALL] + super(Homestead, cls).valid_opcodes() + class Byzantium(Homestead): """ @@ -290,6 +438,15 @@ def call_opcodes( Byzantium, cls ).call_opcodes(block_number, timestamp) + @classmethod + def valid_opcodes( + cls, + ) -> List[Opcodes]: + """ + Returns the list of Opcodes that are valid to work on this fork. + """ + return [Opcodes.RETURNDATASIZE, Opcodes.STATICCALL] + super(Byzantium, cls).valid_opcodes() + class Constantinople(Byzantium): """ @@ -315,6 +472,21 @@ def create_opcodes( Constantinople, cls ).create_opcodes(block_number, timestamp) + @classmethod + def valid_opcodes( + cls, + ) -> List[Opcodes]: + """ + Returns the list of Opcodes that are valid to work on this fork. + """ + return [ + Opcodes.SHL, + Opcodes.SHR, + Opcodes.SAR, + Opcodes.EXTCODEHASH, + Opcodes.CREATE2, + ] + super(Constantinople, cls).valid_opcodes() + class ConstantinopleFix(Constantinople, solc_name="constantinople"): """ @@ -336,6 +508,15 @@ def precompiles(cls, block_number: int = 0, timestamp: int = 0) -> List[Address] """ return [Address(9)] + super(Istanbul, cls).precompiles(block_number, timestamp) + @classmethod + def valid_opcodes( + cls, + ) -> List[Opcodes]: + """ + Returns the list of Opcodes that are valid to work on this fork. + """ + return [Opcodes.CHAINID, Opcodes.SELFBALANCE] + super(Istanbul, cls).valid_opcodes() + # Glacier forks skipped, unless explicitly specified class MuirGlacier(Istanbul, solc_name="istanbul", ignore=True): @@ -392,6 +573,15 @@ def contract_creating_tx_types(cls, block_number: int = 0, timestamp: int = 0) - """ return [2] + super(London, cls).contract_creating_tx_types(block_number, timestamp) + @classmethod + def valid_opcodes( + cls, + ) -> List[Opcodes]: + """ + Returns the list of Opcodes that are valid to work on this fork. + """ + return [Opcodes.BASEFEE] + super(London, cls).valid_opcodes() + # Glacier forks skipped, unless explicitly specified class ArrowGlacier(London, solc_name="london", ignore=True): @@ -471,6 +661,15 @@ def engine_new_payload_version( """ return 2 + @classmethod + def valid_opcodes( + cls, + ) -> List[Opcodes]: + """ + Returns the list of Opcodes that are valid to work on this fork. + """ + return [Opcodes.PUSH0] + super(Shanghai, cls).valid_opcodes() + class Cancun(Shanghai): """ @@ -572,6 +771,21 @@ def engine_new_payload_beacon_root(cls, block_number: int = 0, timestamp: int = """ return True + @classmethod + def valid_opcodes( + cls, + ) -> List[Opcodes]: + """ + Returns the list of Opcodes that are valid to work on this fork. + """ + return [ + Opcodes.BLOBHASH, + Opcodes.BLOBBASEFEE, + Opcodes.TLOAD, + Opcodes.TSTORE, + Opcodes.MCOPY, + ] + super(Cancun, cls).valid_opcodes() + class Prague(Cancun): """ diff --git a/src/ethereum_test_tools/tests/test_code.py b/src/ethereum_test_tools/tests/test_code.py index a1540ed729..8846db1feb 100644 --- a/src/ethereum_test_tools/tests/test_code.py +++ b/src/ethereum_test_tools/tests/test_code.py @@ -21,6 +21,7 @@ from ethereum_test_specs import StateTest from ethereum_test_types import Alloc, Environment, Transaction from ethereum_test_vm import Opcodes as Op +from ethereum_test_vm import UndefinedOpcodes from evm_transition_tool import GethTransitionTool from ..code import CalldataCase, Case, Conditional, Initcode, Solc, Switch, Yul @@ -640,3 +641,14 @@ def test_switch(tx_data: bytes, switch_bytecode: bytes, expected_storage: Mappin fixture_format=FixtureFormats.BLOCKCHAIN_TEST, eips=None, ) + + +def test_full_opcode_range(): + """ + Test that the full opcode range is covered by the opcode set defined by + Opcodes and UndefineOpcodes. + """ + assert len(set(Op) & set(UndefinedOpcodes)) == 0 + full_possible_opcode_set = set(Op) | set(UndefinedOpcodes) + assert len(full_possible_opcode_set) == 256 + assert set(op.hex() for op in full_possible_opcode_set) == set(f"{i:02x}" for i in range(256)) diff --git a/tests/frontier/opcodes/test_all_opcodes.py b/tests/frontier/opcodes/test_all_opcodes.py new file mode 100644 index 0000000000..e2e9188696 --- /dev/null +++ b/tests/frontier/opcodes/test_all_opcodes.py @@ -0,0 +1,108 @@ +""" +Call every possible opcode and test that the subcall is successful +if the opcode is supported by the fork supports and fails otherwise. +""" + +from typing import Dict + +import pytest + +from ethereum_test_forks import Fork +from ethereum_test_tools import ( + Account, + Address, + Alloc, + Bytecode, + Environment, + StateTestFiller, + Transaction, +) +from ethereum_test_tools.vm.opcode import Opcode +from ethereum_test_tools.vm.opcode import Opcodes as Op +from ethereum_test_tools.vm.opcode import UndefinedOpcodes + +REFERENCE_SPEC_GIT_PATH = "N/A" +REFERENCE_SPEC_VERSION = "N/A" + + +def prepare_stack(opcode: Opcode) -> Bytecode: + """Prepare valid stack for opcode""" + if opcode == Op.CREATE: + return Op.MSTORE(0, 0x6001600155) + Op.PUSH1(5) + Op.PUSH1(27) + Op.PUSH1(5) + if opcode == Op.CREATE2: + return Op.MSTORE(0, 0x6001600155) + Op.PUSH1(1) + Op.PUSH1(5) + Op.PUSH1(27) + Op.PUSH1(5) + if opcode == Op.JUMPI: + return Op.PUSH1(1) + Op.PUSH1(5) + if opcode == Op.JUMP: + return Op.PUSH1(3) + return Op.PUSH1(0x01) * 32 + + +def prepare_suffix(opcode: Opcode) -> Bytecode: + """Prepare after opcode instructions""" + if opcode == Op.JUMPI or opcode == Op.JUMP: + return Op.JUMPDEST + return Op.STOP + + +@pytest.mark.valid_from("Frontier") +def test_all_opcodes(state_test: StateTestFiller, pre: Alloc, fork: Fork): + """ + Test each possible opcode on the fork with a single contract that + calls each opcode in succession. Check that each subcall passes + if the opcode is supported and fails otherwise. + """ + code_worked = 1000 + + code_contract: Dict[Opcode, Address] = {} + for opcode in sorted(set(Op) | set(UndefinedOpcodes)): + code_contract[opcode] = pre.deploy_contract( + balance=10, + code=prepare_stack(opcode) + opcode + prepare_suffix(opcode), + storage={}, + ) + + # EVM code to make the call and store the result + contract_address = pre.deploy_contract( + code=sum( + Op.SSTORE( + Op.PUSH1(opcode.int()), + Op.CALL(1_000_000, opcode_address, 0, 0, 0, 0, 0), + ) + for opcode, opcode_address in code_contract.items() + ) + + Op.SSTORE(code_worked, 1) + + Op.STOP, + ) + + post = { + contract_address: Account( + storage={**{opcode.int(): 1 for opcode in fork.valid_opcodes()}, code_worked: 1} + ), + } + + tx = Transaction( + sender=pre.fund_eoa(), + gas_limit=500_000_000, + to=contract_address, + data=b"", + value=0, + protected=False, + ) + + state_test(env=Environment(), pre=pre, post=post, tx=tx) + + +@pytest.mark.valid_from("Cancun") +def test_cover_revert(state_test: StateTestFiller, pre: Alloc): + """Cover state revert from original tests for the coverage script""" + tx = Transaction( + sender=pre.fund_eoa(), + gas_limit=1_000_000, + data=Op.SSTORE(1, 1) + Op.REVERT, + to=b"", + value=0, + protected=False, + ) + + state_test(env=Environment(), pre=pre, post={}, tx=tx) From 6bb88772b0d02288a917611b82d42e3f778bd2ee Mon Sep 17 00:00:00 2001 From: winsvega Date: Wed, 28 Aug 2024 19:04:28 +0300 Subject: [PATCH 10/17] feat(tests): EOF - EIP-3540/EIP-4200: Move and rename oritests (#731) * remove tests that are already covered * move test section header body mismatch test to a separate file * rename valid invalid into jump opcodes * remove already covered tests * test_sction_header_body_mismatch adjust for auto stack and inputs * implement suggested tests * rebase on main * refactor(tests): use extend_with_defaults * style(tests): fix spelling in comments * correct rjumpv at the end test * Update tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py --------- Co-authored-by: danceratopz Co-authored-by: Mario Vega --- .../test_example_valid_invalid.py | 368 ------------------ .../test_section_header_body_mismatch.py | 146 +++++++ .../eip4200_relative_jumps/test_rjumpi.py | 34 ++ .../eip4200_relative_jumps/test_rjumpv.py | 19 + 4 files changed, 199 insertions(+), 368 deletions(-) delete mode 100644 tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_example_valid_invalid.py create mode 100644 tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_header_body_mismatch.py diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_example_valid_invalid.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_example_valid_invalid.py deleted file mode 100644 index 560ec8d51f..0000000000 --- a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_example_valid_invalid.py +++ /dev/null @@ -1,368 +0,0 @@ -""" -EOF Classes example use -""" - -import pytest - -from ethereum_test_exceptions.exceptions import EOFExceptionInstanceOrList -from ethereum_test_tools import EOFException, EOFTestFiller -from ethereum_test_tools import Opcodes as Op -from ethereum_test_tools.eof.v1 import Container, Section - -from .. import EOF_FORK_NAME - -REFERENCE_SPEC_GIT_PATH = "EIPS/eip-3540.md" -REFERENCE_SPEC_VERSION = "8dcb0a8c1c0102c87224308028632cc986a61183" - -pytestmark = pytest.mark.valid_from(EOF_FORK_NAME) - - -@pytest.mark.parametrize( - "eof_code,expected_hex_bytecode,exception", - [ - pytest.param( - # Check that simple EOF1 deploys - Container( - name="EOF1V0001", - sections=[ - Section.Code( - code=Op.ADDRESS + Op.POP + Op.STOP, - ), - Section.Data("0xef"), - ], - ), - "ef000101000402000100030400010000800001305000ef", - None, - id="simple_eof_1_deploy", - ), - pytest.param( - # Check that valid EOF1 can include 0xFE, the designated invalid opcode - Container( - name="EOF1V0004", - sections=[ - Section.Code( - code=Op.ADDRESS + Op.POP + Op.INVALID, - ), - Section.Data("0x0bad60A7"), - ], - ), - "ef0001010004020001000304000400008000013050fe0bad60A7", - None, - id="fe_opcode_ok", - ), - pytest.param( - # Check that EOF1 with a bad end of sections number fails - Container( - name="EOF1I0005", - sections=[ - Section.Code( - code=Op.ADDRESS + Op.POP + Op.STOP, - ), - Section.Data("0xef"), - ], - header_terminator=b"\xFF", - ), - "ef00010100040200010003040001ff00800001305000ef", - [EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - id="headers_terminator_invalid", - ), - pytest.param( - # Check that code that uses a new style relative jump succeeds - Container( - name="EOF1V0008", - sections=[ - Section.Code( - code=Op.PUSH0 - + Op.RJUMPI[3] - + Op.RJUMP[3] - + Op.RJUMP[3] - + Op.RJUMP[-6] - + Op.STOP, - ), - Section.Data("0x0bad60A7"), - ], - ), - "ef0001010004020001000E04000400008000015FE10003E00003E00003E0FFFA000bad60A7", - None, - id="rjump_valid", - ), - pytest.param( - # Check that code that uses a new style conditional jump succeeds - Container( - name="EOF1V0011", - sections=[ - Section.Code( - code=Op.PUSH1(1) + Op.RJUMPI[1] + Op.NOOP + Op.STOP, - ), - Section.Data("0x0bad60A7"), - ], - ), - "ef0001010004020001000704000400008000016001E100015B000bad60A7", - None, - id="rjumpi_valid", - ), - pytest.param( - # Sections that end with a legit terminating opcode are OK - Container( - name="EOF1V0014", - sections=[ - Section.Code( - code=Op.PUSH0 - + Op.CALLDATALOAD - + Op.RJUMPV[0, 3, 6, 9] - + Op.JUMPF[1] - + Op.JUMPF[2] - + Op.JUMPF[3] - + Op.CALLF[4] - + Op.STOP, - ), - Section.Code( - code=Op.PUSH0 + Op.PUSH0 + Op.RETURN, - ), - Section.Code( - code=Op.PUSH0 + Op.PUSH0 + Op.REVERT, - ), - Section.Code(code=Op.INVALID), - Section.Code( - code=Op.RETF, - code_outputs=0, - ), - Section.Data("0x0bad60A7"), - ], - ), - "EF0001010014020005001900030003000100010400040000800001008000020080000200800000000" - "000005f35e2030000000300060009e50001e50002e50003e30004005f5ff35f5ffdfee40bad60a7", - None, - id="rjumpv_section_terminator_valid", - ), - pytest.param( - # Check that jump tables work - Container( - name="EOF1V0013", - sections=[ - Section.Code( - code=Op.PUSH1(1) - + Op.RJUMPV[2, 0] - + Op.ADDRESS - + Op.POP - + Op.ADDRESS - + Op.POP - + Op.STOP, - ), - Section.Data("0x0bad60A7"), - ], - ), - "ef0001010004020001000D04000400008000016001E2010002000030503050000bad60A7", - None, - id="jump_tables_valid", - ), - pytest.param( - # Check that jumps into the middle on an opcode are not allowed - Container( - name="EOF1I0019", - sections=[ - Section.Code( - code=Op.PUSH1(1) - + Op.RJUMPV[b"\x02\x00\x02\xFF\xFF"] - + Op.ADDRESS - + Op.POP - + Op.ADDRESS - + Op.POP - + Op.STOP, - ), - Section.Data("0x0bad60A7"), - ], - ), - "ef0001010004020001000D04000400008000016001E2020002FFFF30503050000bad60A7", - EOFException.INVALID_RJUMP_DESTINATION, - id="rjump_invalid", - ), - pytest.param( - # TODO why here is expected an exception by the comment but test is valid - # Check that you can't get to the same opcode with two different stack heights - Container( - name="EOF1I0020", - sections=[ - Section.Code( - code=Op.PUSH1(1) + Op.RJUMPI[1] + Op.ADDRESS + Op.NOOP + Op.STOP, - ), - Section.Data("0x0bad60A7"), - ], - ), - "ef0001010004020001000804000400008000016001E10001305B000bad60A7", - None, - id="jump_to_opcode_ok", - ), - pytest.param( - # Check that jumps into the middle on an opcode are not allowed - Container( - name="EOF1I0019", - sections=[ - Section.Code(code=Op.RJUMP[3] + Op.RJUMP[2] + Op.RJUMP[-6] + Op.STOP), - Section.Data("0x0bad60A7"), - ], - ), - "ef0001010004020001000A0400040000800000E00003E00002E0FFFA000bad60A7", - EOFException.INVALID_RJUMP_DESTINATION, - id="rjump_3_2_m6_fails", - ), - pytest.param( - # Check that jumps into the middle on an opcode are not allowed - Container( - name="EOF1I0019", - sections=[ - Section.Code( - code=Op.PUSH1(0) - + Op.PUSH1(0) - + Op.PUSH1(0) - + Op.RJUMPI[3] - + Op.RJUMPI[2] - + Op.RJUMPI[-6] - + Op.STOP, - ), - Section.Data("0x0bad60A7"), - ], - ), - "ef000101000402000100100400040000800003600060006000E10003E10002E1FFFA000bad60A7", - EOFException.INVALID_RJUMP_DESTINATION, - id="push1_0_0_0_rjump_3_2_m6_fails", - ), - pytest.param( - # Check that that code that uses removed opcodes fails - Container( - name="EOF1I0015", - sections=[ - Section.Code( - code=Op.PUSH1(3) + Op.JUMP + Op.JUMPDEST + Op.STOP, - ), - Section.Data("0xef"), - ], - ), - "ef0001010004020001000504000100008000016003565B00ef", - EOFException.UNDEFINED_INSTRUCTION, - id="jump_jumpdest_fails", - ), - ], -) -def test_example_valid_invalid( - eof_test: EOFTestFiller, - eof_code: Container, - expected_hex_bytecode: str, - exception: EOFException | None, -): - """ - Verify eof container construction and exception - """ - # TODO remove this after Container class implementation is reliable - assert bytes(eof_code).hex() == bytes.fromhex(expected_hex_bytecode).hex() - - eof_test( - data=eof_code, - expect_exception=exception, - ) - - -@pytest.mark.parametrize( - "skip_header_listing, skip_body_listing, skip_types_body_listing, skip_types_header_listing," - "expected_code, expected_exception", - [ - pytest.param( - True, # second section is not in code header array - True, # second section is not in container's body (it's code bytes) - False, # but it's code input bytes still listed in container's body - False, # but it's code input bytes size still added to types section size - "ef000101000802000100030400040000800001000000003050000bad60A7", - [EOFException.INVALID_TYPE_SECTION_SIZE, EOFException.INVALID_SECTION_BODIES_SIZE], - id="drop_code_section_and_header", - ), - pytest.param( - True, # second section is not in code header array - False, # second section code is in container's body (3050000) - False, # but it's code input bytes still listed in container's body - False, # but it's code input bytes size still added to types section size - "ef000101000802000100030400040000800001000000003050003050000bad60A7", - [EOFException.INVALID_TYPE_SECTION_SIZE, EOFException.INVALID_SECTION_BODIES_SIZE], - id="drop_code_header", - ), - pytest.param( - False, # second section is mentioned in code header array (0003) - True, # second section is not in container's body (it's code bytes) - False, # but it's code input bytes still listed in container's body - False, # but it's code input bytes size still added to types section size - "ef0001010008020002000300030400040000800001000000003050000bad60A7", - [EOFException.UNREACHABLE_CODE_SECTIONS, EOFException.TOPLEVEL_CONTAINER_TRUNCATED], - id="drop_code_section", - ), - pytest.param( - False, # second section is mentioned in code header array (0003) - False, # second section code is in container's body (3050000) - False, # but it's code input bytes still listed in container's body - False, # but it's code input bytes size still added to types section size - "ef0001010008020002000300030400040000800001000000003050003050000bad60A7", - EOFException.UNREACHABLE_CODE_SECTIONS, - id="layout_ok_code_bad", - ), - pytest.param( - # Data 17 test case of valid invalid eof ori filler - True, # second section is not in code header array - True, # second section is not in container's body (it's code bytes) - True, # it's code input bytes are not listed in container's body (00000000) - False, # but it's code input bytes size still added to types section size - "ef0001010008020001000304000400008000013050000bad60a7", - [EOFException.INVALID_TYPE_SECTION_SIZE, EOFException.INVALID_SECTION_BODIES_SIZE], - id="drop_types_header", - ), - pytest.param( - True, # second section is not in code header array - True, # second section is not in container's body (it's code bytes) - True, # it's code input bytes are not listed in container's body (00000000) - True, # and it is bytes size is not counted in types header - "ef0001010004020001000304000400008000013050000bad60a7", - None, - id="drop_everything", - ), - ], -) -def test_code_section_header_body_mismatch( - eof_test: EOFTestFiller, - skip_header_listing: bool, - skip_body_listing: bool, - skip_types_body_listing: bool, - skip_types_header_listing: bool, - expected_code: str, - expected_exception: EOFExceptionInstanceOrList | None, -): - """ - Inconsistent number of code sections (between types and code) - """ - eof_code = Container( - name="EOF1I0018", - sections=[ - Section.Code( - code=Op.ADDRESS + Op.POP + Op.STOP, - ), - Section.Code( - code=Op.ADDRESS + Op.POP + Op.STOP, - code_inputs=0, - code_outputs=0, - max_stack_height=0, - # weather to not mention it in code section header list - skip_header_listing=skip_header_listing, - # weather to not print it's code in containers body - skip_body_listing=skip_body_listing, - # weather to not print it's input bytes in containers body - skip_types_body_listing=skip_types_body_listing, - # weather to not calculate it's input bytes size in types section's header - skip_types_header_listing=skip_types_header_listing, - ), - Section.Data("0x0bad60A7"), - ], - ) - - # TODO remove this after Container class implementation is reliable - assert bytes(eof_code).hex() == bytes.fromhex(expected_code).hex() - - eof_test( - data=eof_code, - expect_exception=expected_exception, - ) diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_header_body_mismatch.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_header_body_mismatch.py new file mode 100644 index 0000000000..b0f2e58866 --- /dev/null +++ b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_header_body_mismatch.py @@ -0,0 +1,146 @@ +""" +EOF Container construction test +""" + +import pytest + +from ethereum_test_exceptions.exceptions import EOFExceptionInstanceOrList +from ethereum_test_tools import EOFException, EOFTestFiller +from ethereum_test_tools import Opcodes as Op +from ethereum_test_tools import extend_with_defaults +from ethereum_test_tools.eof.v1 import Container, Section + +from .. import EOF_FORK_NAME + +REFERENCE_SPEC_GIT_PATH = "EIPS/eip-3540.md" +REFERENCE_SPEC_VERSION = "8dcb0a8c1c0102c87224308028632cc986a61183" + +pytestmark = pytest.mark.valid_from(EOF_FORK_NAME) + + +@pytest.mark.parametrize( + **extend_with_defaults( + defaults=dict( + skip_header_listing=False, # second section is mentioned in code header array + skip_body_listing=False, # second section code is in container's body + skip_types_body_listing=False, # code input bytes not listed in container's body + skip_types_header_listing=False, # code input bytes size not added to types section size # noqa: E501 + expected_code="", + expected_exception=None, + ), + cases=[ + pytest.param( + dict( + skip_header_listing=True, + skip_body_listing=True, + expected_code="ef000101000802000100030400040000800001000000003050000bad60A7", + expected_exception=[ + EOFException.INVALID_TYPE_SECTION_SIZE, + EOFException.INVALID_SECTION_BODIES_SIZE, + ], + ), + id="drop_code_section_and_header", + ), + pytest.param( + dict( + skip_header_listing=True, + skip_body_listing=False, + expected_code="ef000101000802000100030400040000800001000000003050003050000bad60A7", # noqa: E501 + expected_exception=[ + EOFException.INVALID_TYPE_SECTION_SIZE, + EOFException.INVALID_SECTION_BODIES_SIZE, + ], + ), + id="drop_code_header", + ), + pytest.param( + dict( + skip_header_listing=False, + skip_body_listing=True, + expected_code="ef0001010008020002000300030400040000800001000000003050000bad60A7", # noqa: E501 + expected_exception=[ + EOFException.UNREACHABLE_CODE_SECTIONS, + EOFException.TOPLEVEL_CONTAINER_TRUNCATED, + ], + ), + id="drop_code_section", + ), + pytest.param( + dict( + skip_header_listing=False, + skip_body_listing=False, + expected_code="ef0001010008020002000300030400040000800001000000003050003050000bad60A7", # noqa: E501 + expected_exception=EOFException.UNREACHABLE_CODE_SECTIONS, + ), + id="layout_ok_code_bad", + ), + pytest.param( + dict( + skip_header_listing=True, + skip_body_listing=True, + skip_types_body_listing=True, + expected_code="ef0001010008020001000304000400008000013050000bad60a7", + expected_exception=[ + EOFException.INVALID_TYPE_SECTION_SIZE, + EOFException.INVALID_SECTION_BODIES_SIZE, + ], + ), + id="drop_types_header", + ), + pytest.param( + dict( + skip_header_listing=True, + skip_body_listing=True, + skip_types_body_listing=True, + skip_types_header_listing=True, + expected_code="ef0001010004020001000304000400008000013050000bad60a7", + expected_exception=None, + ), + id="drop_everything", + ), + ], + ) +) +def test_code_section_header_body_mismatch( + eof_test: EOFTestFiller, + skip_header_listing: bool, + skip_body_listing: bool, + skip_types_body_listing: bool, + skip_types_header_listing: bool, + expected_code: str, + expected_exception: EOFExceptionInstanceOrList | None, +): + """ + Inconsistent number of code sections (between types and code) + """ + eof_code = Container( + name="EOF1I0018", + sections=[ + Section.Code( + code=Op.ADDRESS + Op.POP + Op.STOP, + ), + Section.Code( + code=Op.ADDRESS + Op.POP + Op.STOP, + code_inputs=0, + code_outputs=0, + max_stack_height=0, + # whether to not mention it in code section header list + skip_header_listing=skip_header_listing, + # whether to not print its code in containers body + skip_body_listing=skip_body_listing, + # whether to not print its input bytes in containers body + skip_types_body_listing=skip_types_body_listing, + # whether to not calculate its input bytes size in types section's header + skip_types_header_listing=skip_types_header_listing, + ), + Section.Data("0x0bad60A7"), + ], + ) + + # TODO remove this after Container class implementation is reliable + assert bytes(eof_code).hex() == bytes.fromhex(expected_code).hex() + + eof_test( + data=eof_code, + expect_exception=expected_exception, + ) diff --git a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py index 10cfa17521..9f92ce26fa 100644 --- a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py +++ b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpi.py @@ -827,3 +827,37 @@ def test_rjumpi_backwards_reference_only( data=container, expect_exception=EOFException.UNREACHABLE_INSTRUCTIONS, ) + + +def test_rjumpi_stack_validation( + eof_test: EOFTestFiller, +): + """ + Check that you can get to the same opcode with two different stack heights + Spec now allows this: + 4.b in https://github.com/ipsilon/eof/blob/main/spec/eof.md#stack-validation + """ + container = Container.Code(code=Op.RJUMPI[1](1) + Op.ADDRESS + Op.NOOP + Op.STOP) + eof_test( + data=container, + expect_exception=None, + ) + + +def test_rjumpi_at_the_end( + eof_test: EOFTestFiller, +): + """ + https://github.com/ipsilon/eof/blob/main/spec/eof.md#stack-validation 4.i: + This implies that the last instruction may be a terminating instruction or RJUMP + """ + eof_test( + data=Container( + sections=[ + Section.Code( + code=Op.PUSH1(0) + Op.PUSH1(0) + Op.RJUMPI[1] + Op.STOP + Op.RJUMPI[-4], + ) + ], + ), + expect_exception=EOFException.MISSING_STOP_OPCODE, + ) diff --git a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py index 286360610b..5bac96cf70 100644 --- a/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py +++ b/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjumpv.py @@ -1125,3 +1125,22 @@ def test_rjumpv_backwards_reference_only( data=container, expect_exception=EOFException.UNREACHABLE_INSTRUCTIONS, ) + + +def test_rjumpv_at_the_end( + eof_test: EOFTestFiller, +): + """ + https://github.com/ipsilon/eof/blob/main/spec/eof.md#stack-validation 4.i: + This implies that the last instruction may be a terminating instruction or RJUMP + """ + eof_test( + data=Container( + sections=[ + Section.Code( + code=Op.PUSH1(0) + Op.PUSH1(0) + Op.RJUMPI[1] + Op.STOP + Op.RJUMPV[-7](1), + ) + ], + ), + expect_exception=EOFException.MISSING_STOP_OPCODE, + ) From c4aa83ccf0963077c85351777e7c65dea9696e97 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Aug 2024 18:11:07 +0200 Subject: [PATCH 11/17] docs: add some dev docs to help using nectos/act (#776) --- docs/dev/index.md | 1 + docs/dev/test_actions_locally.md | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 docs/dev/test_actions_locally.md diff --git a/docs/dev/index.md b/docs/dev/index.md index ec2c423a81..19c2c2984a 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -5,3 +5,4 @@ This documentation is aimed at maintainers of `execution-spec-tests` but may be - [generating documentation](./docs.md). - [coding style](./coding_style.md). - [enabling pre-commit checks](./precommit.md). +- [running github actions locally](./test_actions_locally.md). diff --git a/docs/dev/test_actions_locally.md b/docs/dev/test_actions_locally.md new file mode 100644 index 0000000000..0c47296e08 --- /dev/null +++ b/docs/dev/test_actions_locally.md @@ -0,0 +1,39 @@ +# Testing Github Actions Locally + +The Github Actions workflows can be tested locally using [nektos/act](https://github.com/nektos/act) which allows you to test Github Actions locally, without pushing changes to the remote. + +## Prerequisites + +1. Install the `act` tool, [docs](https://nektosact.com/installation/index.html). +2. Install the Github CLI (`gh`) for authentication: [linux](https://github.com/cli/cli/blob/trunk/docs/install_linux.md), [macos](https://github.com/cli/cli/tree/trunk?tab=readme-ov-file#macos). +3. Authenticate with the Github CLI: + + ```shell + gh auth login + ``` + +## Testing Workflows + +### Testing a Workflow that uses a Matrix Strategy + +```bash + act -j build --workflows .github/workflows/tox_verify.yaml -s GITHUB_TOKEN=$(gh auth token) --matrix python:3.10 + ``` + +### Testing Release Builds + +Release builds require the `ref` input to be specified. To test a release build locally: + +1. Create a JSON file specifying the input data required for a release build (the release tag), e.g, `event.json`: + + ```json + { + "ref": "refs/tags/stable@v4.2.0" + } + ``` + +2. Run `act` and specify the workflow file, the Github token, and the event file: + + ```bash + act -j build --workflows .github/workflows/fixtures_feature.yaml -s GITHUB_TOKEN=$(gh auth token) -e event.json + ``` From bc820c647a9a88915c89d0776a45e9e8547add48 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 29 Aug 2024 19:18:59 +0200 Subject: [PATCH 12/17] feat(fill): add solc plugin and automatic installation of solc (#772) --- .github/actions/build-fixtures/action.yaml | 3 +- .github/workflows/coverage.yaml | 22 +- README.md | 9 +- docs/CHANGELOG.md | 1 + .../executing_tests_command_line.md | 54 +++-- docs/getting_started/quick_start.md | 11 +- pyproject.toml | 2 +- pytest-framework.ini | 2 + pytest.ini | 1 + src/pytest_plugins/filler/filler.py | 41 +--- src/pytest_plugins/filler/solc.py | 103 +++++++++ src/pytest_plugins/filler/tests/conftest.py | 15 ++ src/pytest_plugins/filler/tests/test_solc.py | 199 ++++++++++++++++++ tox.ini | 6 +- whitelist.txt | 3 + 15 files changed, 386 insertions(+), 86 deletions(-) create mode 100644 src/pytest_plugins/filler/solc.py create mode 100644 src/pytest_plugins/filler/tests/conftest.py create mode 100644 src/pytest_plugins/filler/tests/test_solc.py diff --git a/.github/actions/build-fixtures/action.yaml b/.github/actions/build-fixtures/action.yaml index 4e2de96dc2..ea88950b67 100644 --- a/.github/actions/build-fixtures/action.yaml +++ b/.github/actions/build-fixtures/action.yaml @@ -30,8 +30,7 @@ runs: python -m venv env source env/bin/activate pip install -e . - solc-select use ${{ steps.properties.outputs.solc }} --always-install - fill -n ${{ steps.evm-builder.outputs.x-dist }} --evm-bin=${{ steps.evm-builder.outputs.evm-bin }} ${{ steps.properties.outputs.fill-params }} --output=fixtures_${{ inputs.name }}.tar.gz --build-name ${{ inputs.name }} + fill -n ${{ steps.evm-builder.outputs.x-dist }} --evm-bin=${{ steps.evm-builder.outputs.evm-bin }} --solc-version=${{ steps.properties.outputs.solc }} ${{ steps.properties.outputs.fill-params }} --output=fixtures_${{ inputs.name }}.tar.gz --build-name ${{ inputs.name }} - uses: actions/upload-artifact@v4 with: name: fixtures_${{ inputs.name }} diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index c036f9a440..885b696c44 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -3,7 +3,7 @@ name: Evmone Coverage Report on: pull_request: paths: - - 'converted-ethereum-tests.txt' # This triggers the workflow only for changes in file.txt + - "converted-ethereum-tests.txt" # This triggers the workflow only for changes in file.txt jobs: evmone-coverage-diff: @@ -37,20 +37,19 @@ jobs: python3 -m venv ./venv/ source ./venv/bin/activate pip install -e . - solc-select use 0.8.25 --always-install # Required to fill .py tests - name: Build GO EVM uses: ./.github/actions/build-evm-client/geth id: evm-builder with: - type: 'main' + type: "main" - name: Build EVMONE EVM uses: ./.github/actions/build-evm-client/evmone id: evm-builder2 with: - type: 'main' + type: "main" - name: Checkout ethereum/tests uses: actions/checkout@v4 @@ -69,7 +68,6 @@ jobs: sparse-checkout: | Cancun/GeneralStateTests - # This command diffs the file and filters in new lines - name: Parse converted tests from converted-ethereum-tests.txt run: | @@ -78,7 +76,7 @@ jobs: files=$(echo "$lines" | grep -oP '(?<=\+).+\.json') if [ -z "$files" ]; then - echo "Error: No new JSON files found in converted-ethereum-tests.txt" + echo "Error: No new JSON files found in converted-ethereum-tests.txt" exit 1 fi @@ -114,13 +112,13 @@ jobs: fi if [ $file_found -eq 0 ]; then - echo "Error: Failed to find the test file $file in test repo" + echo "Error: Failed to find the test file $file in test repo" exit 1 fi done - # This command diffs the .py scripts introduced by a PR + # This command diffs the .py scripts introduced by a PR - name: Parse and fill introduced test sources run: | python3 -m venv ./venv/ @@ -153,12 +151,12 @@ jobs: mkdir -p fixtures/eof_tests echo "$files" | while read line; do file=$(echo "$line" | cut -c 3-) - fill $file --until=Cancun --evm-bin evmone-t8n || true >> filloutput.log 2>&1 - (fill $file --fork=CancunEIP7692 --evm-bin evmone-t8n -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 + fill $file --until=Cancun --evm-bin evmone-t8n --solc-version=0.8.25 || true >> filloutput.log 2>&1 + (fill $file --fork=CancunEIP7692 --evm-bin evmone-t8n --solc-version=0.8.25 -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 done if grep -q "FAILURES" filloutput.log; then - echo "Error: failed to generate .py tests." + echo "Error: failed to generate .py tests." exit 1 fi if [ "${{ matrix.driver }}" = "retesteth" ] && grep -q "passed" filloutputEOF.log; then @@ -174,7 +172,7 @@ jobs: filesEOF=$(find fixtures/eof_tests -type f -name "*.json") if [ -z "$filesState" ] && [ -z "$filesEOF" ]; then echo "Error: No filled JSON fixtures found in fixtures." - exit 1 + exit 1 fi PATCH_TEST_PATH=${{ github.workspace }}/evmtest_coverage/coverage/PATCH_TESTS diff --git a/README.md b/README.md index 1c0142b09a..b5401fa99d 100644 --- a/README.md +++ b/README.md @@ -82,20 +82,19 @@ The following requires a Python 3.10, 3.11 or 3.12 installation. ### Quick Start -This guide installs stable versions of the required external (go-ethereum) `evm` and `solc` executables and will only enable generation of test fixtures for features deployed to mainnet. In order to generate fixtures for features under active development, you can follow the steps below and then follow the [additional steps in the online doc](https://ethereum.github.io/execution-spec-tests/getting_started/executing_tests_dev_fork/). +This guide installs stable versions of the external (go-ethereum) `evm` executable and will only enable generation of test fixtures for features deployed to mainnet. In order to generate fixtures for features under active development, you can follow the steps below and then follow the [additional steps in the online doc](https://ethereum.github.io/execution-spec-tests/getting_started/executing_tests_dev_fork/). -1. Ensure go-ethereum's `evm` tool and `solc` ([0.8.20](https://github.com/ethereum/solidity/releases/tag/v0.8.20), [0.8.21](https://github.com/ethereum/solidity/releases/tag/v0.8.21), [0.8.22](https://github.com/ethereum/solidity/releases/tag/v0.8.22), [0.8.23](https://github.com/ethereum/solidity/releases/tag/v0.8.23) supported) are in your path. Either build the required versions, or alternatively: +1. Ensure go-ethereum's `evm` tool is in your path. Either build the required version, or alternatively: ```console sudo add-apt-repository -y ppa:ethereum/ethereum sudo apt-get update - sudo apt-get install ethereum solc + sudo apt-get install ethereum ``` More help: - [geth installation doc](https://geth.ethereum.org/docs/getting-started/installing-geth#ubuntu-via-ppas). - - [solc installation doc](https://docs.soliditylang.org/en/latest/installing-solidity.html#linux-packages). Help for other platforms is available in the [online doc](https://ethereum.github.io/execution-spec-tests/getting_started/quick_start/). @@ -129,7 +128,7 @@ This guide installs stable versions of the required external (go-ethereum) `evm` ![Screenshot of pytest test collection console output](docs/getting_started/img/pytest_run_example.png) Check: - 1. The versions of the `evm` and `solc` tools are as expected (your versions may differ from those in the highlighted box). + 1. The versions of the `evm` tool is as expected (your versions may differ from those in the highlighted box). 2. The corresponding fixture file has been generated: ```console diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 2cdcf4f31f..d1f6acec71 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -32,6 +32,7 @@ Test fixtures for use by clients are available for each release on the [Github r - ✨ Added `Container.Init` to `ethereum_test_types.EOF.V1` package, which allows generation of an EOF init container more easily ([#739](https://github.com/ethereum/execution-spec-tests/pull/739)). - ✨ Introduce method valid_opcodes() to the fork class ([#748](https://github.com/ethereum/execution-spec-tests/pull/748)). - 🐞 Fixed `consume` exit code return values, ensuring that pytest's return value is correctly propagated to the shell. This allows the shell to accurately reflect the test results (e.g., failures) based on the pytest exit code ([#765](https://github.com/ethereum/execution-spec-tests/pull/765)). +- ✨ Added a new flag `--solc-version` to the `fill` command, which allows the user to specify the version of the Solidity compiler to use when compiling Yul source code; this version will now be automatically downloaded by `fill` via [`solc-select`](https://github.com/crytic/solc-select) ([#772](https://github.com/ethereum/execution-spec-tests/pull/772). ### 🔧 EVM Tools diff --git a/docs/getting_started/executing_tests_command_line.md b/docs/getting_started/executing_tests_command_line.md index e79b3be5a1..a3a1303086 100644 --- a/docs/getting_started/executing_tests_command_line.md +++ b/docs/getting_started/executing_tests_command_line.md @@ -114,17 +114,36 @@ fill --help Output: ```text -usage: fill [-h] [--evm-bin EVM_BIN] [--traces] [--verify-fixtures] - [--verify-fixtures-bin VERIFY_FIXTURES_BIN] [--solc-bin SOLC_BIN] +usage: fill [-h] [--strict-alloc] [--ca-start CA_START] [--ca-incr CA_INCR] + [--evm-code-type EVM_CODE_TYPE] [--solc-bin SOLC_BIN] + [--solc-version SOLC_VERSION] [--evm-bin EVM_BIN] [--traces] + [--verify-fixtures] [--verify-fixtures-bin VERIFY_FIXTURES_BIN] [--filler-path FILLER_PATH] [--output OUTPUT] [--flat-output] - [--single-fixture-per-file] [--no-html] [--strict-alloc] - [--ca-start CA_START] [--ca-incr CA_INCR] [--build-name BUILD_NAME] - [--evm-dump-dir EVM_DUMP_DIR] [--forks] [--fork FORK] [--from FROM] - [--until UNTIL] [--test-help] + [--single-fixture-per-file] [--no-html] [--build-name BUILD_NAME] + [--index] [--evm-dump-dir EVM_DUMP_DIR] [--forks] [--fork FORK] + [--from FROM] [--until UNTIL] [--test-help] options: -h, --help show this help message and exit +Arguments defining pre-allocation behavior.: + --strict-alloc [DEBUG ONLY] Disallows deploying a contract in a + predefined address. + --ca-start CA_START, --contract-address-start CA_START + The starting address from which tests will deploy + contracts. + --ca-incr CA_INCR, --contract-address-increment CA_INCR + The address increment value to each deployed contract by + a test. + --evm-code-type EVM_CODE_TYPE + Type of EVM code to deploy in each test by default. + +Arguments defining the solc executable: + --solc-bin SOLC_BIN Path to a solc executable (for Yul source compilation). + No default; if unspecified `--solc-version` is used. + --solc-version SOLC_VERSION + Version of the solc compiler to use. Default: 0.8.24. + Arguments defining evm executable behavior: --evm-bin EVM_BIN Path to an evm executable that provides `t8n`. Default: First 'evm' entry in PATH. @@ -140,18 +159,14 @@ Arguments defining evm executable behavior: Path to an evm executable that provides the `blocktest` command. Default: The first (geth) 'evm' entry in PATH. -Arguments defining the solc executable: - --solc-bin SOLC_BIN Path to a solc executable (for Yul source compilation). - Default: First 'solc' entry in PATH. - Arguments defining filler location and output: --filler-path FILLER_PATH Path to filler directives - --output OUTPUT Directory path to store the generated test fixtures. Can - be deleted. If the specified path ends in '.tar.gz', then - the specified tarball is additionally created (the - fixtures are still written to the specified path without - '.tar.gz' suffix). Default: './fixtures'. + --output OUTPUT Directory path to store the generated test fixtures. If + the specified path ends in '.tar.gz', then the specified + tarball is additionally created (the fixtures are still + written to the specified path without the '.tar.gz' + suffix). Can be deleted. Default: './fixtures'. --flat-output Output each test case in the directory without the folder structure. --single-fixture-per-file @@ -161,17 +176,10 @@ Arguments defining filler location and output: --no-html Don't generate an HTML test report (in the output directory). The --html flag can be used to specify a different path. - --strict-alloc [DEBUG ONLY] Disallows deploying a contract in a - predefined address. - --ca-start CA_START, --contract-address-start CA_START - The starting address from which tests will deploy - contracts. - --ca-incr CA_INCR, --contract-address-increment CA_INCR - The address increment value to each deployed contract by - a test. --build-name BUILD_NAME Specify a build name for the fixtures.ini file, e.g., 'stable'. + --index Generate an index file for all produced fixtures. Arguments defining debug behavior: --evm-dump-dir EVM_DUMP_DIR, --t8n-dump-dir EVM_DUMP_DIR diff --git a/docs/getting_started/quick_start.md b/docs/getting_started/quick_start.md index 5af386d553..17d401faf7 100644 --- a/docs/getting_started/quick_start.md +++ b/docs/getting_started/quick_start.md @@ -1,25 +1,24 @@ # Quick Start !!! info "Testing features under active development" - The EVM features under test must be implemented in the `evm` tool and `solc` executables that are used by the execution-spec-tests framework. The following guide installs stable versions of these tools. + The EVM features under test must be implemented in the `evm` tool and `solc` executables that are used by the execution-spec-tests framework. The following guide installs the stable version of the geth `evm`; `solc` will be installed by the `fill` command. To test features under active development, start with this base configuration and then follow the steps in [executing tests for features under development](./executing_tests_dev_fork.md). The following requires a Python 3.10, 3.11 or 3.12 installation. -1. Ensure `go-ethereum`'s `evm` tool and `solc` ([0.8.20](https://github.com/ethereum/solidity/releases/tag/v0.8.20), [0.8.21](https://github.com/ethereum/solidity/releases/tag/v0.8.21), [0.8.22](https://github.com/ethereum/solidity/releases/tag/v0.8.22), [0.8.23](https://github.com/ethereum/solidity/releases/tag/v0.8.23) supported) are in your path. Either build the required versions, or alternatively: +1. Ensure `go-ethereum`'s `evm` tool is in your path. Either build the required version, or alternatively: === "Ubuntu" ```console sudo add-apt-repository -y ppa:ethereum/ethereum sudo apt-get update - sudo apt-get install ethereum solc + sudo apt-get install ethereum ``` More help: - [geth installation doc](https://geth.ethereum.org/docs/getting-started/installing-geth#ubuntu-via-ppas). - - [solc installation doc](https://docs.soliditylang.org/en/latest/installing-solidity.html#linux-packages). === "macOS" @@ -32,7 +31,6 @@ The following requires a Python 3.10, 3.11 or 3.12 installation. More help: - [geth installation doc](https://geth.ethereum.org/docs/getting-started/installing-geth#macos-via-homebrew). - - [solc installation doc](https://docs.soliditylang.org/en/latest/installing-solidity.html#macos-packages). === "Windows" @@ -44,7 +42,6 @@ The following requires a Python 3.10, 3.11 or 3.12 installation. More help: - [geth installation doc](https://geth.ethereum.org/docs/getting-started/installing-geth#windows). - - [solc static binaries doc](https://docs.soliditylang.org/en/latest/installing-solidity.html#static-binaries). 2. Clone the [execution-spec-tests](https://github.com/ethereum/execution-spec-tests) repo and install its dependencies (it's recommended to use a virtual environment for the installation): @@ -80,7 +77,7 @@ The following requires a Python 3.10, 3.11 or 3.12 installation. Check: - 1. The versions of the `evm` and `solc` tools are as expected (your versions may differ from those in the highlighted box). + 1. The versions of the `evm` tool is as expected (your versions may differ from those in the highlighted box). 2. The generated HTML test report by clicking the link at the bottom of the console output. 3. The corresponding fixture file has been generated: diff --git a/pyproject.toml b/pyproject.toml index c433d36239..02fb2f6773 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ dependencies = [ "semver>=3.0.1,<4", "pydantic>=2.8.0,<2.9", "rich>=13.7.0,<14", - "solc-select>=1.0.4", + "solc-select>=1.0.4,<2", "filelock>=3.15.1,<4", ] diff --git a/pytest-framework.ini b/pytest-framework.ini index 54e79389dc..a14f35c467 100644 --- a/pytest-framework.ini +++ b/pytest-framework.ini @@ -5,6 +5,8 @@ python_files= test_*.py testpaths = src +markers = + run_in_serial addopts = -p pytester --ignore=src/pytest_plugins/consume/direct/test_via_direct.py diff --git a/pytest.ini b/pytest.ini index 309f013e2f..b0e8832c53 100644 --- a/pytest.ini +++ b/pytest.ini @@ -8,6 +8,7 @@ markers = pre_alloc_modify addopts = -p pytest_plugins.filler.pre_alloc + -p pytest_plugins.filler.solc -p pytest_plugins.filler.filler -p pytest_plugins.forks.forks -p pytest_plugins.spec_version_checker.spec_version_checker diff --git a/src/pytest_plugins/filler/filler.py b/src/pytest_plugins/filler/filler.py index 5ea02fe633..ae5a98128d 100644 --- a/src/pytest_plugins/filler/filler.py +++ b/src/pytest_plugins/filler/filler.py @@ -5,6 +5,7 @@ and that modifies pytest hooks in order to fill test specs for all tests and writes the generated fixtures to file. """ + import argparse import configparser import datetime @@ -23,14 +24,12 @@ from ethereum_test_fixtures import FixtureCollector, FixtureFormats, TestInfo from ethereum_test_forks import ( Fork, - Frontier, Paris, get_closest_fork_with_solc_support, get_forks_with_solc_support, ) from ethereum_test_specs import SPEC_TYPES, BaseTest from ethereum_test_tools import Yul -from ethereum_test_tools.code import Solc from ethereum_test_tools.utility.versioning import ( generate_github_url, get_current_commit_hash_or_tag, @@ -117,18 +116,6 @@ def pytest_addoption(parser: pytest.Parser): ), ) - solc_group = parser.getgroup("solc", "Arguments defining the solc executable") - solc_group.addoption( - "--solc-bin", - action="store", - dest="solc_bin", - default=None, - help=( - "Path to a solc executable (for Yul source compilation). " - "Default: First 'solc' entry in PATH." - ), - ) - test_group = parser.getgroup("tests", "Arguments defining filler location and output") test_group.addoption( "--filler-path", @@ -269,18 +256,14 @@ def pytest_configure(config): "The Besu t8n tool does not work well with the xdist plugin; use -n=0.", returncode=pytest.ExitCode.USAGE_ERROR, ) - config.solc_version = Solc(config.getoption("solc_bin")).version - if config.solc_version < Frontier.solc_min_version(): - pytest.exit( - f"Unsupported solc version: {config.solc_version}. Minimum required version is " - f"{Frontier.solc_min_version()}", - returncode=pytest.ExitCode.USAGE_ERROR, - ) - config.stash[metadata_key]["Tools"] = { - "t8n": t8n.version(), - "solc": str(config.solc_version), - } + if "Tools" not in config.stash[metadata_key]: + config.stash[metadata_key]["Tools"] = { + "t8n": t8n.version(), + } + else: + config.stash[metadata_key]["Tools"]["t8n"] = t8n.version() + args = ["fill"] + [str(arg) for arg in config.invocation_params.args] for i in range(len(args)): if " " in args[i]: @@ -419,14 +402,6 @@ def verify_fixtures_bin(request: pytest.FixtureRequest) -> Path | None: return request.config.getoption("verify_fixtures_bin") -@pytest.fixture(autouse=True, scope="session") -def solc_bin(request: pytest.FixtureRequest): - """ - Returns the configured solc binary path. - """ - return request.config.getoption("solc_bin") - - @pytest.fixture(autouse=True, scope="session") def t8n(request: pytest.FixtureRequest, evm_bin: Path) -> Generator[TransitionTool, None, None]: """ diff --git a/src/pytest_plugins/filler/solc.py b/src/pytest_plugins/filler/solc.py new file mode 100644 index 0000000000..01b1d1a565 --- /dev/null +++ b/src/pytest_plugins/filler/solc.py @@ -0,0 +1,103 @@ +""" +Pytest plugin for configuring and installing the solc compiler. +""" + +from argparse import ArgumentTypeError +from shutil import which + +import pytest +import solc_select.solc_select as solc_select # type: ignore +from pytest_metadata.plugin import metadata_key # type: ignore +from semver import Version + +from ethereum_test_forks import Frontier +from ethereum_test_tools.code import Solc + +DEFAULT_SOLC_VERSION = "0.8.24" + + +def pytest_addoption(parser: pytest.Parser): + """ + Adds command-line options to pytest. + """ + solc_group = parser.getgroup("solc", "Arguments defining the solc executable") + solc_group.addoption( + "--solc-bin", + action="store", + dest="solc_bin", + type=str, + default=None, + help=( + "Path to a solc executable (for Yul source compilation). " + "No default; if unspecified `--solc-version` is used." + ), + ) + solc_group.addoption( + "--solc-version", + action="store", + dest="solc_version", + default=None, + help=f"Version of the solc compiler to use. Default: {DEFAULT_SOLC_VERSION}.", + ) + + +@pytest.hookimpl(tryfirst=True) +def pytest_configure(config: pytest.Config): + """ + Ensure that the specified solc version is: + - available if --solc_bin has been specified, + - installed via solc_select if --solc_version has been specified. + """ + solc_bin = config.getoption("solc_bin") + solc_version = config.getoption("solc_version") + + if solc_bin and solc_version: + raise pytest.UsageError( + "You cannot specify both --solc-bin and --solc-version. Please choose one." + ) + + if solc_bin: + # will raise an error if the solc binary is not found. + solc_version_semver = Solc(config.getoption("solc_bin")).version + else: + # if no solc binary is specified, use solc-select + solc_version = solc_version or DEFAULT_SOLC_VERSION + try: + version, _ = solc_select.current_version() + except ArgumentTypeError: + version = None + if version != solc_version: + if config.getoption("verbose") > 0: + print(f"Setting solc version {solc_version} via solc-select...") + try: + solc_select.switch_global_version(solc_version, always_install=True) + except Exception as e: + message = f"Failed to install solc version {solc_version}: {e}. " + if isinstance(e, ArgumentTypeError): + message += "\nList available versions using `uv run solc-select install`." + pytest.exit(message, returncode=pytest.ExitCode.USAGE_ERROR) + solc_version_semver = Version.parse(solc_version) + config.option.solc_bin = which("solc") # save for fixture + + if "Tools" not in config.stash[metadata_key]: + config.stash[metadata_key]["Tools"] = { + "solc": str(solc_version_semver), + } + else: + config.stash[metadata_key]["Tools"]["solc"] = str(solc_version_semver) + + if solc_version_semver < Frontier.solc_min_version(): + pytest.exit( + f"Unsupported solc version: {solc_version}. Minimum required version is " + f"{Frontier.solc_min_version()}", + returncode=pytest.ExitCode.USAGE_ERROR, + ) + config.solc_version = solc_version_semver # type: ignore + + +@pytest.fixture(autouse=True, scope="session") +def solc_bin(request: pytest.FixtureRequest): + """ + Returns the configured solc binary path. + """ + return request.config.getoption("solc_bin") diff --git a/src/pytest_plugins/filler/tests/conftest.py b/src/pytest_plugins/filler/tests/conftest.py new file mode 100644 index 0000000000..ad9a626306 --- /dev/null +++ b/src/pytest_plugins/filler/tests/conftest.py @@ -0,0 +1,15 @@ +""" +Local configuration for filler tests. +""" + +import os + +import pytest + + +def pytest_runtest_setup(item): + """Hook to skip tests if running with pytest-xdist in parallel.""" + marker = item.get_closest_marker(name="run_in_serial") + if marker is not None: + if os.getenv("PYTEST_XDIST_WORKER_COUNT") not in [None, "1"]: + pytest.skip("Skipping test because pytest-xdist is running with more than one worker.") diff --git a/src/pytest_plugins/filler/tests/test_solc.py b/src/pytest_plugins/filler/tests/test_solc.py new file mode 100644 index 0000000000..f59cc0d5f8 --- /dev/null +++ b/src/pytest_plugins/filler/tests/test_solc.py @@ -0,0 +1,199 @@ +""" +Tests for the solc plugin. +""" + +import os +import shutil +import tempfile +from pathlib import Path + +import pytest +import solc_select.constants # type: ignore +import solc_select.solc_select # type: ignore + +pytestmark = [pytest.mark.run_in_serial] + + +@pytest.fixture(scope="module") +def create_clean_solc_select_environment(request): + """ + Setup: Copies solc artifacts to a temporary location before starting tests + Teardown: Restores the artifacts after tests are done. + """ + try: + test_session_solc_version, _ = solc_select.solc_select.current_version() + except Exception as e: + raise Exception( + "Error in setup: ensure you've called `solc-select use ` before running the " + f"framework tests (exception: {e})" + ) + + artifacts_dir = solc_select.constants.ARTIFACTS_DIR + global_version_file = solc_select.constants.SOLC_SELECT_DIR.joinpath("global-version") + + with tempfile.TemporaryDirectory() as temp_dir: + temp_dir_path = Path(temp_dir) + + # Copy global-version and artifacts to a temporary directory and delete them + if global_version_file.exists(): + shutil.copy(global_version_file, temp_dir_path / "global-version") + os.remove(global_version_file) + if artifacts_dir.exists(): + shutil.copytree(artifacts_dir, temp_dir_path / "artifacts", dirs_exist_ok=True) + shutil.rmtree(artifacts_dir) + + os.makedirs(artifacts_dir, exist_ok=True) # this won't get recreated by solc-select + + yield + # Teardown: Restore the original files and directory from the temporary location + if global_version_file.exists(): + os.remove(global_version_file) + if artifacts_dir.exists(): + shutil.rmtree(artifacts_dir) + + # Restore the global-version file and artifacts + if (temp_dir_path / "global-version").exists(): + shutil.copy(temp_dir_path / "global-version", global_version_file) + if (temp_dir_path / "artifacts").exists(): + shutil.copytree(temp_dir_path / "artifacts", artifacts_dir, dirs_exist_ok=True) + + # Restore the solc version + solc_select.solc_select.switch_global_version( + str(test_session_solc_version), always_install=True + ) + + +@pytest.mark.usefixtures("create_clean_solc_select_environment") +@pytest.mark.parametrize("solc_version", ["0.8.21", "0.8.26"]) +class TestSolcVersion: # noqa: D101 + def test_solc_versions_flag(self, pytester, solc_version): + """ + Ensure that the version specified by the `--solc-version` gets installed and is used. + """ + pytester.makeconftest( + f""" + import pytest + from ethereum_test_tools.code import Solc + + @pytest.fixture(autouse=True) + def check_solc_version(request, solc_bin): + assert request.config.getoption("solc_version") == "{solc_version}" + assert Solc(solc_bin).version == "{solc_version}" + """ + ) + pytester.copy_example(name="pytest.ini") + pytester.copy_example(name="tests/homestead/yul/test_yul_example.py") + result = pytester.runpytest( + "-v", + "--fork=Homestead", + "--flat-output", # required as copy_example doesn't copy to "tests/"" sub-folder + "-m", + "state_test", + f"--solc-version={solc_version}", + ) + + result.assert_outcomes( + passed=1, + failed=0, + skipped=0, + errors=0, + ) + + +def test_solc_version_too_old(pytester): + """ + Test the plugin exits with a UsageError if a version prior to Frontier is specified. + """ + old_solc_version = "0.8.19" + pytester.copy_example(name="pytest.ini") + test_path = pytester.copy_example(name="tests/homestead/yul/test_yul_example.py") + result = pytester.runpytest( + "-v", "--fork=Frontier", "--solc-version", old_solc_version, test_path + ) + assert result.ret == pytest.ExitCode.USAGE_ERROR + assert "Unsupported solc version" in "\n".join(result.stderr.lines) + + +def test_unknown_solc_version(pytester): + """ + Test the plugin exits with a UsageError if a version unknown to solc-select is specified. + """ + unknown_solc_version = "420.69.0" + pytester.copy_example(name="pytest.ini") + test_path = pytester.copy_example(name="tests/homestead/yul/test_yul_example.py") + result = pytester.runpytest( + "-v", "--fork=Frontier", "--solc-version", unknown_solc_version, test_path + ) + assert result.ret == pytest.ExitCode.USAGE_ERROR + stderr = "\n".join(result.stderr.lines) + assert f"Unknown version '{unknown_solc_version}'" in stderr + assert "List available versions using" in stderr + + +def test_bad_solc_flag_combination(pytester): + """ + Test the plugin exits with a UsageError if both `--solc-bin` and `--solc-version` are + specified. + """ + pytester.copy_example(name="pytest.ini") + test_path = pytester.copy_example(name="tests/homestead/yul/test_yul_example.py") + result = pytester.runpytest( + "-v", "--fork=Frontier", "--solc-version=0.8.24", "--solc-bin=solc", test_path + ) + assert result.ret == pytest.ExitCode.USAGE_ERROR + assert "You cannot specify both --solc-bin and --solc-version" in "\n".join( + result.stderr.lines + ) + + +@pytest.mark.usefixtures("create_clean_solc_select_environment") +class TestSolcBin: + """ + Test the `--solc-bin` flag. + """ + + @pytest.fixture() + def solc_version(self): # noqa: D102 + return "0.8.25" + + @pytest.fixture() + def solc_bin(self, solc_version): + """ + Returns an available solc binary. + """ + solc_select.solc_select.switch_global_version(solc_version, always_install=True) + bin_path = Path(f"solc-{solc_version}") / f"solc-{solc_version}" + return solc_select.constants.ARTIFACTS_DIR.joinpath(bin_path) + + def test_solc_bin(self, pytester, solc_version, solc_bin): + """ + Ensure that the version specified by the `--solc-version` gets installed and is used. + """ + pytester.makeconftest( + f""" + import pytest + from ethereum_test_tools.code import Solc + + @pytest.fixture(autouse=True) + def check_solc_version(request, solc_bin): + # test via solc_bin fixture + assert Solc(solc_bin).version == "{solc_version}" + """ + ) + pytester.copy_example(name="pytest.ini") + pytester.copy_example(name="tests/homestead/yul/test_yul_example.py") + result = pytester.runpytest( + "-v", + "--fork=Homestead", + "-m", + "state_test", + "--flat-output", # required as copy_example doesn't copy to "tests/"" sub-folder, + f"--solc-bin={solc_bin}", + ) + + result.assert_outcomes( + passed=1, + failed=0, + skipped=0, + errors=0, + ) diff --git a/tox.ini b/tox.ini index c040c34cec..cb4aff42b0 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,6 @@ eip7692 = CancunEIP7692 [testenv] package = wheel wheel_build_env = .pkg -commands_pre = solc-select use 0.8.24 --always-install [testenv:framework] description = Run checks on helper libraries and test framework @@ -22,6 +21,8 @@ extras = src = src +commands_pre = solc-select use 0.8.24 --always-install + commands = fname8 {[testenv:framework]src} isort {[testenv:framework]src} --check --diff @@ -29,6 +30,7 @@ commands = flake8 {[testenv:framework]src} mypy {[testenv:framework]src} pytest -c ./pytest-framework.ini -n auto + pytest -c ./pytest-framework.ini -m run_in_serial [testenv:py3] description = An alias for the 'framework' tox environment @@ -84,8 +86,6 @@ extras = lint docs -commands_pre = # Override commands pre to not run solc-select install - setenv = SPEC_TESTS_AUTO_GENERATE_FILES = true # Required for `cairosvg` so tox can find `libcairo-2`. diff --git a/whitelist.txt b/whitelist.txt index 0da8f75883..daa9464202 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -222,6 +222,7 @@ isort's ispkg itemName jimporter +joinpath jq js json @@ -240,7 +241,9 @@ lllc london macOS mainnet +makefiles makereport +makeconftest marioevz markdownlint md From b8d318fa59bb8c9eea66a3cfee3973638d4f3b99 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Fri, 30 Aug 2024 00:28:12 +0200 Subject: [PATCH 13/17] fix(consume): bugfixes when --input is a remote url (#778) --- src/cli/gen_index.py | 1 + src/pytest_plugins/consume/consume.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cli/gen_index.py b/src/cli/gen_index.py index 4c2dad6392..19e49ae6a2 100644 --- a/src/cli/gen_index.py +++ b/src/cli/gen_index.py @@ -137,6 +137,7 @@ def generate_fixtures_index( total_files = count_json_files_exclude_index(input_path) output_file = Path(f"{input_path}/.meta/index.json") + output_file.parent.mkdir(parents=True, exist_ok=True) # no meta dir in <=v3.0.0 try: root_hash = HashableItem.from_folder(folder_path=input_path).hash() except (KeyError, TypeError): diff --git a/src/pytest_plugins/consume/consume.py b/src/pytest_plugins/consume/consume.py index 4466eda323..8bc0cea2bb 100644 --- a/src/pytest_plugins/consume/consume.py +++ b/src/pytest_plugins/consume/consume.py @@ -57,7 +57,7 @@ def download_and_extract(url: str, base_directory: Path) -> Path: if extract_to.exists(): # skip download if the archive has already been downloaded - return extract_to + return extract_to / "fixtures" extract_to.mkdir(parents=True, exist_ok=False) response = requests.get(url) From 0a42a182fd027a7c77c33499d3fdaf8d39407b15 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Fri, 30 Aug 2024 11:17:26 -0600 Subject: [PATCH 14/17] feat(plugins/forks): Fix covariant markers, add `selector`/`marks` parameters (#762) * fix(plugins/forks): fix case where the covariant fork method returns tuple or list * fix(plugins/forks): Disallow args in `with_all` markers * fix(plugins/forks): Add test * feat(plugins/forks): Fix covariant markers * feat(plugins/forks): Support for markers on covariant values * tests(filler): check correct error string is reported * test(forks): add marks_selector tests for `with_all` decorators * tests(forks): remove bad test case from previous commit * Apply suggestions from code review Co-authored-by: danceratopz * refactor(forks): Move helpers to forks library * fix(plugins/forks): Fix `with_all` `marks` field * feat(docs): Add `marks` field to docs * fix(docs): tox * docs: changelog --------- Co-authored-by: danceratopz --- docs/CHANGELOG.md | 4 +- docs/writing_tests/test_markers.md | 18 ++ src/ethereum_test_forks/__init__.py | 12 +- src/ethereum_test_forks/helpers.py | 62 +++- src/pytest_plugins/forks/forks.py | 270 ++++++++++-------- src/pytest_plugins/forks/tests/__init__.py | 3 + .../forks/tests/test_covariant_markers.py | 230 +++++++++++---- .../tests/test_fork_parametrizer_types.py | 214 ++++++++++++++ whitelist.txt | 1 + 9 files changed, 630 insertions(+), 184 deletions(-) create mode 100644 src/pytest_plugins/forks/tests/__init__.py create mode 100644 src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d1f6acec71..e07bf5fa71 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -32,7 +32,9 @@ Test fixtures for use by clients are available for each release on the [Github r - ✨ Added `Container.Init` to `ethereum_test_types.EOF.V1` package, which allows generation of an EOF init container more easily ([#739](https://github.com/ethereum/execution-spec-tests/pull/739)). - ✨ Introduce method valid_opcodes() to the fork class ([#748](https://github.com/ethereum/execution-spec-tests/pull/748)). - 🐞 Fixed `consume` exit code return values, ensuring that pytest's return value is correctly propagated to the shell. This allows the shell to accurately reflect the test results (e.g., failures) based on the pytest exit code ([#765](https://github.com/ethereum/execution-spec-tests/pull/765)). -- ✨ Added a new flag `--solc-version` to the `fill` command, which allows the user to specify the version of the Solidity compiler to use when compiling Yul source code; this version will now be automatically downloaded by `fill` via [`solc-select`](https://github.com/crytic/solc-select) ([#772](https://github.com/ethereum/execution-spec-tests/pull/772). +- ✨ Added a new flag `--solc-version` to the `fill` command, which allows the user to specify the version of the Solidity compiler to use when compiling Yul source code; this version will now be automatically downloaded by `fill` via [`solc-select`](https://github.com/crytic/solc-select) ([#772](https://github.com/ethereum/execution-spec-tests/pull/772)). +- 🐞 Fix usage of multiple `@pytest.mark.with_all*` markers which shared parameters, such as `with_all_call_opcodes` and `with_all_create_opcodes` which shared `evm_code_type`, and now only parametrize compatible values ([#762](https://github.com/ethereum/execution-spec-tests/pull/762)). +- ✨ Added `selector` and `marks` fields to all `@pytest.mark.with_all*` markers, which allows passing lambda functions to select or mark specific parametrized values (see [documentation](https://ethereum.github.io/execution-spec-tests/main/writing_tests/test_markers/#covariant-marker-keyword-arguments) for more information) ([#762](https://github.com/ethereum/execution-spec-tests/pull/762)). ### 🔧 EVM Tools diff --git a/docs/writing_tests/test_markers.md b/docs/writing_tests/test_markers.md index 34df2eb58d..ce43edab4d 100644 --- a/docs/writing_tests/test_markers.md +++ b/docs/writing_tests/test_markers.md @@ -253,6 +253,24 @@ def test_something_with_all_tx_types( Ideally, the lambda function should be used to explicitly filter out values that are not compatible with the test (exclusive filter), rather than explicitly selecting values (inclusive filter), as the parametrized values might change with future forks. +#### `marks` + +A marker, list of markers, or a lambda function that can be used to add additional markers to the test. + +```python +import pytest + +@pytest.mark.with_all_tx_types( + marks=lambda tx_type: pytest.mark.skip("incompatible") if tx_type == 1 else None, +) +@pytest.mark.valid_from("London") +def test_something_with_all_tx_types_but_skip_type_1(state_test_only, tx_type): + assert tx_type != 1 + ... +``` + +In this example, the test will be skipped if `tx_type` is equal to 1 by returning a `pytest.mark.skip` marker, and return `None` otherwise. + ## Other Markers ### `@pytest.mark.slow` diff --git a/src/ethereum_test_forks/__init__.py b/src/ethereum_test_forks/__init__.py index 456679967b..6a254f812f 100644 --- a/src/ethereum_test_forks/__init__.py +++ b/src/ethereum_test_forks/__init__.py @@ -33,8 +33,12 @@ get_deployed_forks, get_development_forks, get_forks, + get_forks_with_no_descendants, + get_forks_with_no_parents, get_forks_with_solc_support, get_forks_without_solc_support, + get_from_until_fork_set, + get_last_descendants, get_transition_forks, transition_fork_from_to, transition_fork_to, @@ -65,12 +69,16 @@ "get_transition_forks", "forks_from", "forks_from_until", + "get_closest_fork_with_solc_support", "get_deployed_forks", "get_development_forks", - "get_forks", + "get_forks_with_no_descendants", + "get_forks_with_no_parents", "get_forks_with_solc_support", "get_forks_without_solc_support", - "get_closest_fork_with_solc_support", + "get_forks", + "get_from_until_fork_set", + "get_last_descendants", "transition_fork_from_to", "transition_fork_to", ] diff --git a/src/ethereum_test_forks/helpers.py b/src/ethereum_test_forks/helpers.py index 62da80568d..2e09217a74 100644 --- a/src/ethereum_test_forks/helpers.py +++ b/src/ethereum_test_forks/helpers.py @@ -1,7 +1,7 @@ """ Helper methods to resolve forks during test filling """ -from typing import List, Optional +from typing import List, Optional, Set from semver import Version @@ -103,6 +103,66 @@ def get_transition_forks() -> List[Fork]: return transition_forks +def get_from_until_fork_set( + forks: Set[Fork], forks_from: Set[Fork], forks_until: Set[Fork] +) -> Set[Fork]: + """ + Get the fork range from forks_from to forks_until. + """ + resulting_set = set() + for fork_from in forks_from: + for fork_until in forks_until: + for fork in forks: + if fork <= fork_until and fork >= fork_from: + resulting_set.add(fork) + return resulting_set + + +def get_forks_with_no_parents(forks: Set[Fork]) -> Set[Fork]: + """ + Get the forks with no parents in the inheritance hierarchy. + """ + resulting_forks: Set[Fork] = set() + for fork in forks: + parents = False + for next_fork in forks - {fork}: + if next_fork < fork: + parents = True + break + if not parents: + resulting_forks = resulting_forks | {fork} + return resulting_forks + + +def get_forks_with_no_descendants(forks: Set[Fork]) -> Set[Fork]: + """ + Get the forks with no descendants in the inheritance hierarchy. + """ + resulting_forks: Set[Fork] = set() + for fork in forks: + descendants = False + for next_fork in forks - {fork}: + if next_fork > fork: + descendants = True + break + if not descendants: + resulting_forks = resulting_forks | {fork} + return resulting_forks + + +def get_last_descendants(forks: Set[Fork], forks_from: Set[Fork]) -> Set[Fork]: + """ + Get the last descendant of a class in the inheritance hierarchy. + """ + resulting_forks: Set[Fork] = set() + forks = get_forks_with_no_descendants(forks) + for fork_from in forks_from: + for fork in forks: + if fork >= fork_from: + resulting_forks = resulting_forks | {fork} + return resulting_forks + + def transition_fork_from_to(fork_from: Fork, fork_to: Fork) -> Fork | None: """ Returns the transition fork that transitions to and from the specified diff --git a/src/pytest_plugins/forks/forks.py b/src/pytest_plugins/forks/forks.py index 2bfd2ba83c..342d76208e 100644 --- a/src/pytest_plugins/forks/forks.py +++ b/src/pytest_plugins/forks/forks.py @@ -7,9 +7,10 @@ import textwrap from dataclasses import dataclass, field from types import FunctionType -from typing import Any, List, Set +from typing import Any, Callable, List, Set, Tuple import pytest +from _pytest.mark.structures import ParameterSet from pytest import Metafunc from ethereum_test_forks import ( @@ -17,6 +18,9 @@ ForkAttribute, get_deployed_forks, get_forks, + get_forks_with_no_parents, + get_from_until_fork_set, + get_last_descendants, get_transition_forks, transition_fork_to, ) @@ -58,14 +62,26 @@ def pytest_addoption(parser): ) +@dataclass(kw_only=True) +class MarkedValue: + """ + A processed value for a covariant parameter. + + Value can be a list for inclusive parameters. + """ + + value: Any + marks: List[pytest.Mark | pytest.MarkDecorator] = field(default_factory=list) + + @dataclass(kw_only=True) class ForkCovariantParameter: """ Value list for a fork covariant parameter in a given fork. """ - name: str - values: List[Any] + names: List[str] + values: List[List[MarkedValue]] @dataclass(kw_only=True) @@ -75,43 +91,48 @@ class ForkParametrizer: """ fork: Fork - mark: pytest.MarkDecorator | None = None fork_covariant_parameters: List[ForkCovariantParameter] = field(default_factory=list) + marks: List[pytest.MarkDecorator | pytest.Mark] = field(default_factory=list) - def get_parameter_names(self) -> List[str]: + @property + def parameter_names(self) -> List[str]: """ Return the parameter names for the test case. """ parameter_names = ["fork"] for p in self.fork_covariant_parameters: - if "," in p.name: - parameter_names.extend(p.name.split(",")) - else: - parameter_names.append(p.name) + parameter_names.extend(p.names) return parameter_names - def get_parameter_values(self) -> List[Any]: + @property + def parameter_values(self) -> List[ParameterSet]: """ Return the parameter values for the test case. """ param_value_combinations = [ - params + # Flatten the list of values for each parameter + list(itertools.chain(*params)) for params in itertools.product( - [self.fork], + # Add the fork so it is multiplied by the other parameters. + # It's a list of lists because all parameters are, but it will + # flattened after the product. + [[MarkedValue(value=self.fork)]], + # Add the values for each parameter, all of them are lists of at least one element. *[p.values for p in self.fork_covariant_parameters], ) ] - for i in range(len(param_value_combinations)): - # if the parameter is a tuple, we need to flatten it - param_value_combinations[i] = list( - itertools.chain.from_iterable( - [v] if not isinstance(v, tuple) else v for v in param_value_combinations[i] - ) - ) - return [ - pytest.param(*params, marks=[self.mark] if self.mark else []) - for params in param_value_combinations - ] + + parameter_set_list: List[ParameterSet] = [] + for marked_params in param_value_combinations: + marks = self.marks.copy() + params: List[Any] = [] + for p in marked_params: + params.append(p.value) + if p.marks: + marks.extend(p.marks) + parameter_set_list.append(pytest.param(*params, marks=marks)) + + return parameter_set_list @dataclass(kw_only=True) @@ -124,7 +145,7 @@ class CovariantDescriptor: marker_name: str description: str fork_attribute_name: str - parameter_name: str + parameter_names: List[str] def get_marker(self, metafunc: Metafunc) -> pytest.Mark | None: """ @@ -145,7 +166,41 @@ def check_enabled(self, metafunc: Metafunc) -> bool: """ return self.get_marker(metafunc) is not None - def filter_values(self, metafunc: Metafunc, values: List[Any]) -> List[Any]: + @staticmethod + def process_value( + values: Any | List[Any] | Tuple[Any], + selector: FunctionType, + marks: None + | pytest.Mark + | pytest.MarkDecorator + | List[pytest.Mark | pytest.MarkDecorator] + | Callable[ + [Any], + List[pytest.Mark | pytest.MarkDecorator] | pytest.Mark | pytest.MarkDecorator | None, + ], + ) -> List[List[MarkedValue]]: + """ + Process a value for a covariant parameter. + + The `selector` is applied to values in order to filter them. + """ + if not isinstance(values, tuple) and not isinstance(values, list): + values = [values] + + if selector(*values[: selector.__code__.co_argcount]): + if isinstance(marks, FunctionType): + marks = marks(*values[: marks.__code__.co_argcount]) + assert not isinstance(marks, FunctionType), "marks must be a list or None" + if marks is None: + marks = [] + elif not isinstance(marks, list): + marks = [marks] # type: ignore + + return [[MarkedValue(value=v, marks=marks) for v in values]] + + return [] + + def process_values(self, metafunc: Metafunc, values: List[Any]) -> List[List[MarkedValue]]: """ Filter the values for the covariant parameter. @@ -154,20 +209,23 @@ def filter_values(self, metafunc: Metafunc, values: List[Any]) -> List[Any]: """ marker = self.get_marker(metafunc) assert marker is not None - if len(marker.kwargs) == 0: - return values + assert len(marker.args) == 0, "Only keyword arguments are supported" + kwargs = dict(marker.kwargs) - if "selector" in kwargs: - selector = kwargs.pop("selector") - assert isinstance(selector, FunctionType), "selector must be a function" - filtered_values = [] - for value in values: - if selector(value): - filtered_values.append(value) - values = filtered_values + + selector = kwargs.pop("selector", lambda _: True) + assert isinstance(selector, FunctionType), "selector must be a function" + + marks = kwargs.pop("marks", None) + if len(kwargs) > 0: raise ValueError(f"Unknown arguments to {self.marker_name}: {kwargs}") - return values + + processed_values: List[List[MarkedValue]] = [] + for value in values: + processed_values.extend(self.process_value(value, selector, marks)) + + return processed_values def add_values(self, metafunc: Metafunc, fork_parametrizer: ForkParametrizer) -> None: """ @@ -180,9 +238,9 @@ def add_values(self, metafunc: Metafunc, fork_parametrizer: ForkParametrizer) -> values = get_fork_covariant_values(block_number=0, timestamp=0) assert isinstance(values, list) assert len(values) > 0 - values = self.filter_values(metafunc, values) + values = self.process_values(metafunc, values) fork_parametrizer.fork_covariant_parameters.append( - ForkCovariantParameter(name=self.parameter_name, values=values) + ForkCovariantParameter(names=self.parameter_names, values=values) ) @@ -192,113 +250,53 @@ def add_values(self, metafunc: Metafunc, fork_parametrizer: ForkParametrizer) -> description="marks a test to be parametrized for all tx types at parameter named tx_type" " of type int", fork_attribute_name="tx_types", - parameter_name="tx_type", + parameter_names=["tx_type"], ), CovariantDescriptor( marker_name="with_all_contract_creating_tx_types", description="marks a test to be parametrized for all tx types that can create a contract" " at parameter named tx_type of type int", fork_attribute_name="contract_creating_tx_types", - parameter_name="tx_type", + parameter_names=["tx_type"], ), CovariantDescriptor( marker_name="with_all_precompiles", description="marks a test to be parametrized for all precompiles at parameter named" " precompile of type int", fork_attribute_name="precompiles", - parameter_name="precompile", + parameter_names=["precompile"], ), CovariantDescriptor( marker_name="with_all_evm_code_types", description="marks a test to be parametrized for all EVM code types at parameter named" " `evm_code_type` of type `EVMCodeType`, such as `LEGACY` and `EOF_V1`", fork_attribute_name="evm_code_types", - parameter_name="evm_code_type", + parameter_names=["evm_code_type"], ), CovariantDescriptor( marker_name="with_all_call_opcodes", description="marks a test to be parametrized for all *CALL opcodes at parameter named" " call_opcode, and also the appropriate EVM code type at parameter named evm_code_type", fork_attribute_name="call_opcodes", - parameter_name="call_opcode,evm_code_type", + parameter_names=["call_opcode", "evm_code_type"], ), CovariantDescriptor( marker_name="with_all_create_opcodes", description="marks a test to be parametrized for all *CREATE* opcodes at parameter named" " create_opcode, and also the appropriate EVM code type at parameter named evm_code_type", fork_attribute_name="create_opcodes", - parameter_name="create_opcode,evm_code_type", + parameter_names=["create_opcode", "evm_code_type"], ), CovariantDescriptor( marker_name="with_all_system_contracts", description="marks a test to be parametrized for all system contracts at parameter named" " system_contract of type int", fork_attribute_name="system_contracts", - parameter_name="system_contract", + parameter_names=["system_contract"], ), ] -def get_from_until_fork_set( - forks: Set[Fork], forks_from: Set[Fork], forks_until: Set[Fork] -) -> Set[Fork]: - """ - Get the fork range from forks_from to forks_until. - """ - resulting_set = set() - for fork_from in forks_from: - for fork_until in forks_until: - for fork in forks: - if fork <= fork_until and fork >= fork_from: - resulting_set.add(fork) - return resulting_set - - -def get_forks_with_no_parents(forks: Set[Fork]) -> Set[Fork]: - """ - Get the forks with no parents in the inheritance hierarchy. - """ - resulting_forks: Set[Fork] = set() - for fork in forks: - parents = False - for next_fork in forks - {fork}: - if next_fork < fork: - parents = True - break - if not parents: - resulting_forks = resulting_forks | {fork} - return resulting_forks - - -def get_forks_with_no_descendants(forks: Set[Fork]) -> Set[Fork]: - """ - Get the forks with no descendants in the inheritance hierarchy. - """ - resulting_forks: Set[Fork] = set() - for fork in forks: - descendants = False - for next_fork in forks - {fork}: - if next_fork > fork: - descendants = True - break - if not descendants: - resulting_forks = resulting_forks | {fork} - return resulting_forks - - -def get_last_descendants(forks: Set[Fork], forks_from: Set[Fork]) -> Set[Fork]: - """ - Get the last descendant of a class in the inheritance hierarchy. - """ - resulting_forks: Set[Fork] = set() - forks = get_forks_with_no_descendants(forks) - for fork_from in forks_from: - for fork in forks: - if fork >= fork_from: - resulting_forks = resulting_forks | {fork} - return resulting_forks - - @pytest.hookimpl(tryfirst=True) def pytest_configure(config: pytest.Config): """ @@ -595,12 +593,14 @@ def pytest_generate_tests(metafunc: pytest.Metafunc): ( ForkParametrizer( fork=fork, - mark=pytest.mark.skip( - reason=( - f"Fork '{fork}' unsupported by " - f"'{metafunc.config.getoption('evm_bin')}'." + marks=[ + pytest.mark.skip( + reason=( + f"Fork '{fork}' unsupported by " + f"'{metafunc.config.getoption('evm_bin')}'." + ) ) - ), + ], ) if fork.name() in sorted(list(unsupported_forks)) else ForkParametrizer(fork=fork) @@ -622,17 +622,53 @@ def add_fork_covariant_parameters( covariant_descriptor.add_values(metafunc=metafunc, fork_parametrizer=fork_parametrizer) -def parametrize_fork(metafunc: Metafunc, fork_parametrizers: List[ForkParametrizer]) -> None: +def parameters_from_fork_parametrizer_list( + fork_parametrizers: List[ForkParametrizer], +) -> Tuple[List[str], List[ParameterSet]]: """ - Add the fork parameters to the test function. + Get the parameters from the fork parametrizers. """ param_names: List[str] = [] - param_values: List[Any] = [] + param_values: List[ParameterSet] = [] for fork_parametrizer in fork_parametrizers: if not param_names: - param_names = fork_parametrizer.get_parameter_names() + param_names = fork_parametrizer.parameter_names else: - assert param_names == fork_parametrizer.get_parameter_names() - param_values.extend(fork_parametrizer.get_parameter_values()) - metafunc.parametrize(param_names, param_values, scope="function") + assert param_names == fork_parametrizer.parameter_names + param_values.extend(fork_parametrizer.parameter_values) + + # Remove duplicate parameters + param_1 = 0 + while param_1 < len(param_names): + param_2 = param_1 + 1 + while param_2 < len(param_names): + if param_names[param_1] == param_names[param_2]: + i = 0 + while i < len(param_values): + if param_values[i].values[param_1] != param_values[i].values[param_2]: + del param_values[i] + else: + param_values[i] = pytest.param( + *param_values[i].values[:param_2], + *param_values[i].values[(param_2 + 1) :], + id=param_values[i].id, + marks=param_values[i].marks, + ) + i += 1 + + del param_names[param_2] + else: + param_2 += 1 + param_1 += 1 + + return param_names, param_values + + +def parametrize_fork(metafunc: Metafunc, fork_parametrizers: List[ForkParametrizer]) -> None: + """ + Add the fork parameters to the test function. + """ + metafunc.parametrize( + *parameters_from_fork_parametrizer_list(fork_parametrizers), scope="function" + ) diff --git a/src/pytest_plugins/forks/tests/__init__.py b/src/pytest_plugins/forks/tests/__init__.py new file mode 100644 index 0000000000..0e5c0f2cb7 --- /dev/null +++ b/src/pytest_plugins/forks/tests/__init__.py @@ -0,0 +1,3 @@ +""" +Tests for the forks plugin. +""" diff --git a/src/pytest_plugins/forks/tests/test_covariant_markers.py b/src/pytest_plugins/forks/tests/test_covariant_markers.py index 9af7346205..1ede8a7be6 100644 --- a/src/pytest_plugins/forks/tests/test_covariant_markers.py +++ b/src/pytest_plugins/forks/tests/test_covariant_markers.py @@ -6,7 +6,7 @@ @pytest.mark.parametrize( - "test_function,passed,failed,skipped,errors", + "test_function,outcomes,error_string", [ pytest.param( """ @@ -17,10 +17,8 @@ def test_case(state_test_only, tx_type): pass """, - 3, - 0, - 0, - 0, + dict(passed=3, failed=0, skipped=0, errors=0), + None, id="with_all_tx_types", ), pytest.param( @@ -32,12 +30,74 @@ def test_case(state_test_only, tx_type): def test_case(state_test_only, tx_type): pass """, - 2, - 0, - 0, - 0, + dict(passed=2, failed=0, skipped=0, errors=0), + None, id="with_all_tx_types_with_selector", ), + pytest.param( + """ + import pytest + @pytest.mark.with_all_tx_types( + marks=lambda tx_type: pytest.mark.skip("incompatible") if tx_type == 1 else None, + ) + @pytest.mark.valid_from("Paris") + @pytest.mark.valid_until("Paris") + def test_case(state_test_only, tx_type): + assert tx_type != 1 + """, + dict(passed=2, xpassed=0, failed=0, skipped=1, errors=0), + None, + id="with_all_tx_types_with_marks_lambda", + ), + pytest.param( + """ + import pytest + @pytest.mark.with_all_tx_types(marks=pytest.mark.skip("incompatible")) + @pytest.mark.valid_from("Paris") + @pytest.mark.valid_until("Paris") + def test_case(state_test_only, tx_type): + assert False + """, + dict(passed=0, xpassed=0, failed=0, skipped=3, errors=0), + None, + id="with_all_tx_types_with_marks_lambda", + ), + pytest.param( + """ + import pytest + @pytest.mark.with_all_tx_types(marks=[pytest.mark.skip("incompatible")]) + @pytest.mark.valid_from("Paris") + @pytest.mark.valid_until("Paris") + def test_case(state_test_only, tx_type): + assert False + """, + dict(passed=0, xpassed=0, failed=0, skipped=3, errors=0), + None, + id="with_all_tx_types_with_marks_lambda", + ), + pytest.param( + """ + import pytest + @pytest.mark.with_all_tx_types( + marks=( + lambda tx_type: + [pytest.mark.xfail, pytest.mark.slow] + if tx_type == 1 else None + ), + ) + @pytest.mark.valid_from("Paris") + @pytest.mark.valid_until("Paris") + def test_case(request, state_test_only, tx_type): + mark_names = [mark.name for mark in request.node.iter_markers()] + + assert "state_test" in mark_names + if tx_type == 1: + assert "slow" in mark_names + """, + dict(passed=2, xpassed=1, failed=0, skipped=0, errors=0), + None, + id="with_all_tx_types_with_marks_lambda_multiple_marks", + ), pytest.param( """ import pytest @@ -47,10 +107,8 @@ def test_case(state_test_only, tx_type): def test_case(state_test_only, tx_type): pass """, - 3, - 0, - 0, - 0, + dict(passed=3, failed=0, skipped=0, errors=0), + None, id="with_all_contract_creating_tx_types", ), pytest.param( @@ -62,10 +120,8 @@ def test_case(state_test_only, tx_type): def test_case(state_test_only, tx_type): pass """, - 3, - 0, - 0, - 0, + dict(passed=3, failed=0, skipped=0, errors=0), + None, id="with_all_contract_creating_tx_types", ), pytest.param( @@ -77,10 +133,8 @@ def test_case(state_test_only, tx_type): def test_case(state_test_only, precompile): pass """, - 10, - 0, - 0, - 0, + dict(passed=10, failed=0, skipped=0, errors=0), + None, id="with_all_precompiles", ), pytest.param( @@ -92,10 +146,8 @@ def test_case(state_test_only, precompile): def test_case(state_test_only, evm_code_type): pass """, - 1, - 0, - 0, - 0, + dict(passed=1, failed=0, skipped=0, errors=0), + None, id="with_all_evm_code_types", ), pytest.param( @@ -107,12 +159,40 @@ def test_case(state_test_only, evm_code_type): def test_case(state_test_only, call_opcode): pass """, - 4, - 0, - 0, - 0, + dict(passed=4, failed=0, skipped=0, errors=0), + None, id="with_all_call_opcodes", ), + pytest.param( + """ + import pytest + from ethereum_test_tools import EVMCodeType + @pytest.mark.with_all_call_opcodes( + selector=(lambda _, evm_code_type: evm_code_type == EVMCodeType.LEGACY) + ) + @pytest.mark.valid_from("Cancun") + @pytest.mark.valid_until("Cancun") + def test_case(state_test_only, call_opcode): + pass + """, + dict(passed=4, failed=0, skipped=0, errors=0), + None, + id="with_all_call_opcodes_with_selector_for_evm_code_type", + ), + pytest.param( + """ + import pytest + from ethereum_test_tools import Opcodes as Op + @pytest.mark.with_all_call_opcodes(selector=lambda call_opcode: call_opcode == Op.CALL) + @pytest.mark.valid_from("Cancun") + @pytest.mark.valid_until("Cancun") + def test_case(state_test_only, call_opcode): + pass + """, + dict(passed=1, failed=0, skipped=0, errors=0), + None, + id="with_all_call_opcodes_with_selector", + ), pytest.param( """ import pytest @@ -122,12 +202,38 @@ def test_case(state_test_only, call_opcode): def test_case(state_test_only, create_opcode): pass """, - 2, - 0, - 0, - 0, + dict(passed=2, failed=0, skipped=0, errors=0), + None, id="with_all_create_opcodes", ), + pytest.param( + """ + import pytest + @pytest.mark.with_all_call_opcodes() + @pytest.mark.with_all_precompiles() + @pytest.mark.valid_from("Cancun") + @pytest.mark.valid_until("Cancun") + def test_case(state_test_only, call_opcode, precompile): + pass + """, + dict(passed=4 * 10, failed=0, skipped=0, errors=0), + None, + id="with_all_call_opcodes_and_precompiles", + ), + pytest.param( + """ + import pytest + @pytest.mark.with_all_call_opcodes() + @pytest.mark.with_all_create_opcodes() + @pytest.mark.valid_from("Cancun") + @pytest.mark.valid_until("Cancun") + def test_case(state_test_only, call_opcode, create_opcode): + pass + """, + dict(passed=2 * 4, failed=0, skipped=0, errors=0), + None, + id="with_all_call_opcodes_and_create_opcodes", + ), pytest.param( """ import pytest @@ -137,10 +243,8 @@ def test_case(state_test_only, create_opcode): def test_case(state_test_only, system_contract): pass """, - 1, - 0, - 0, - 0, + dict(passed=1, failed=0, skipped=0, errors=0), + None, id="with_all_system_contracts", ), pytest.param( @@ -152,10 +256,8 @@ def test_case(state_test_only, system_contract): def test_case(state_test_only, tx_type): pass """, - 0, - 0, - 0, - 1, + dict(passed=0, failed=0, skipped=0, errors=1), + "Unknown arguments to with_all_tx_types", id="invalid_covariant_marker_parameter", ), pytest.param( @@ -167,37 +269,39 @@ def test_case(state_test_only, tx_type): def test_case(state_test_only, tx_type): pass """, - 0, - 0, - 0, - 1, + dict(passed=0, failed=0, skipped=0, errors=1), + "selector must be a function", id="invalid_selector", ), + pytest.param( + """ + import pytest + @pytest.mark.with_all_tx_types(lambda tx_type: tx_type != 0) + @pytest.mark.valid_from("Paris") + @pytest.mark.valid_until("Paris") + def test_case(state_test_only, tx_type): + pass + """, + dict(passed=0, failed=0, skipped=0, errors=1), + "Only keyword arguments are supported", + id="selector_as_positional_argument", + ), ], ) def test_fork_covariant_markers( - pytester, - test_function: str, - passed: int, - failed: int, - skipped: int, - errors: int, + pytester, test_function: str, outcomes: dict, error_string: str | None ): """ - Test that a test with an invalid marker cases: - - Creates an outcome with exactly one error. - - Triggers the expected error string in pytest's console output. + Test fork covariant markers in an isolated test session, i.e., in + a `fill` execution. - Each invalid marwith_all_tx_typesker/marker combination is tested with one test in its own test - session. + In the case of an error, check that the expected error string is in the + console output. """ pytester.makepyfile(test_function) pytester.copy_example(name="pytest.ini") result = pytester.runpytest() - result.assert_outcomes( - passed=passed, - failed=failed, - skipped=skipped, - errors=errors, - ) - # assert error_string in "\n".join(result.stdout.lines) + result.assert_outcomes(**outcomes) + if outcomes["errors"]: + assert error_string is not None + assert error_string in "\n".join(result.stdout.lines) diff --git a/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py b/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py new file mode 100644 index 0000000000..3ab2a9c84c --- /dev/null +++ b/src/pytest_plugins/forks/tests/test_fork_parametrizer_types.py @@ -0,0 +1,214 @@ +""" +Test the types used to parametrize forks. +""" + +from typing import List + +import pytest +from _pytest.mark.structures import ParameterSet + +from ethereum_test_forks import Frontier + +from ..forks import ( + ForkCovariantParameter, + ForkParametrizer, + MarkedValue, + parameters_from_fork_parametrizer_list, +) + + +@pytest.mark.parametrize( + "fork_parametrizers,expected_names,expected_parameter_sets", + [ + pytest.param( + [ForkParametrizer(fork=Frontier)], + ["fork"], + [pytest.param(Frontier)], + id="only_fork", + ), + pytest.param( + [ + ForkParametrizer( + fork=Frontier, + fork_covariant_parameters=[ + ForkCovariantParameter( + names=["some_value"], values=[[MarkedValue(value=1)]] + ) + ], + ) + ], + ["fork", "some_value"], + [pytest.param(Frontier, 1)], + id="fork_with_single_covariant_parameter", + ), + pytest.param( + [ + ForkParametrizer( + fork=Frontier, + fork_covariant_parameters=[ + ForkCovariantParameter( + names=["some_value"], + values=[[MarkedValue(value=1)], [MarkedValue(value=2)]], + ) + ], + ) + ], + ["fork", "some_value"], + [pytest.param(Frontier, 1), pytest.param(Frontier, 2)], + id="fork_with_single_covariant_parameter_multiple_values", + ), + pytest.param( + [ + ForkParametrizer( + fork=Frontier, + fork_covariant_parameters=[ + ForkCovariantParameter( + names=["some_value"], + values=[ + [MarkedValue(value=1, marks=[pytest.mark.some_mark])], + [MarkedValue(value=2)], + ], + ) + ], + ) + ], + ["fork", "some_value"], + [pytest.param(Frontier, 1, marks=[pytest.mark.some_mark]), pytest.param(Frontier, 2)], + id="fork_with_single_covariant_parameter_multiple_values_one_mark", + ), + pytest.param( + [ + ForkParametrizer( + fork=Frontier, + fork_covariant_parameters=[ + ForkCovariantParameter( + names=["some_value"], values=[[MarkedValue(value=1)]] + ), + ForkCovariantParameter( + names=["another_value"], values=[[MarkedValue(value=2)]] + ), + ], + ) + ], + ["fork", "some_value", "another_value"], + [pytest.param(Frontier, 1, 2)], + id="fork_with_multiple_covariant_parameters", + ), + pytest.param( + [ + ForkParametrizer( + fork=Frontier, + fork_covariant_parameters=[ + ForkCovariantParameter( + names=["some_value"], values=[[MarkedValue(value=1)]] + ), + ForkCovariantParameter( + names=["another_value"], + values=[[MarkedValue(value=2)], [MarkedValue(value=3)]], + ), + ], + ) + ], + ["fork", "some_value", "another_value"], + [pytest.param(Frontier, 1, 2), pytest.param(Frontier, 1, 3)], + id="fork_with_multiple_covariant_parameters_multiple_values", + ), + pytest.param( + [ + ForkParametrizer( + fork=Frontier, + fork_covariant_parameters=[ + ForkCovariantParameter( + names=["some_value", "another_value"], + values=[ + [MarkedValue(value=1), MarkedValue(value="a")], + [MarkedValue(value=2), MarkedValue(value="b")], + ], + ) + ], + ) + ], + ["fork", "some_value", "another_value"], + [pytest.param(Frontier, 1, "a"), pytest.param(Frontier, 2, "b")], + id="fork_with_single_multi_value_covariant_parameter_multiple_values", + ), + pytest.param( + [ + ForkParametrizer( + fork=Frontier, + fork_covariant_parameters=[ + ForkCovariantParameter( + names=["some_value", "another_value"], + values=[ + [MarkedValue(value=1), MarkedValue(value="a")], + [MarkedValue(value=2), MarkedValue(value="b")], + ], + ), + ForkCovariantParameter( + names=["yet_another_value", "last_value"], + values=[ + [MarkedValue(value=3), MarkedValue(value="x")], + [MarkedValue(value=4), MarkedValue(value="y")], + ], + ), + ], + ) + ], + ["fork", "some_value", "another_value", "yet_another_value", "last_value"], + [ + pytest.param(Frontier, 1, "a", 3, "x"), + pytest.param(Frontier, 1, "a", 4, "y"), + pytest.param(Frontier, 2, "b", 3, "x"), + pytest.param(Frontier, 2, "b", 4, "y"), + ], + id="fork_with_multiple_multi_value_covariant_parameter_multiple_values", + ), + pytest.param( + [ + ForkParametrizer( + fork=Frontier, + fork_covariant_parameters=[ + ForkCovariantParameter( + names=["shared_value", "different_value_1"], + values=[ + [MarkedValue(value=1), MarkedValue(value="a")], + [MarkedValue(value=2), MarkedValue(value="b")], + ], + ), + ForkCovariantParameter( + names=["shared_value", "different_value_2"], + values=[ + [MarkedValue(value=1), MarkedValue(value="x")], + [MarkedValue(value=2), MarkedValue(value="y")], + ], + ), + ], + ) + ], + ["fork", "shared_value", "different_value_1", "different_value_2"], + [ + pytest.param(Frontier, 1, "a", "x"), + pytest.param(Frontier, 2, "b", "y"), + ], + id="fork_with_multiple_multi_value_covariant_parameter_shared_values", + ), + ], +) +def test_fork_parametrizer( + fork_parametrizers: List[ForkParametrizer], + expected_names: List[str], + expected_parameter_sets: List[ParameterSet], +): + """ + Test that the fork parametrizer correctly parametrizes tests based on the fork name. + """ + parameter_names, values = parameters_from_fork_parametrizer_list(fork_parametrizers) + assert parameter_names == expected_names + assert len(values) == len(expected_parameter_sets) + for i in range(len(values)): + assert len(values[i].values) == len(expected_parameter_sets[i].values) + for j in range(len(values[i].values)): + assert values[i].values[j] == expected_parameter_sets[i].values[j] + assert len(values[i].marks) == len(expected_parameter_sets[i].marks) + for j in range(len(values[i].marks)): + assert values[i].marks[j] == expected_parameter_sets[i].marks[j] # type: ignore diff --git a/whitelist.txt b/whitelist.txt index daa9464202..45087e7b35 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -424,6 +424,7 @@ xF xFA xFD xFF +xpassed yaml YAML yml From 3fc3792c16dd69fc6bfeb7a25f3043fed7f1bdbc Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Mon, 2 Sep 2024 09:48:34 -0600 Subject: [PATCH 15/17] feat(docs/tests): EOF: Update tracker, add unimplemented tests (#773) * feat(types/eof): Allow skipping joining same-type sections in header * refactor(tests): refactor `container.py` into `test_container_validation.py` * fix(docs): EOF tracker updates * fix(docs/tests): more EOF tracker updates * fix(docs): minor typo --- src/ethereum_test_types/eof/v1/__init__.py | 9 +- .../eip3540_eof_v1/container.py | 694 ----------- .../eip3540_eof_v1/test_code_validation.py | 67 - .../test_container_validation.py | 1091 ++++++++++++++++- tests/prague/eip7692_eof_v1/tracker.md | 150 ++- 5 files changed, 1169 insertions(+), 842 deletions(-) delete mode 100644 tests/prague/eip7692_eof_v1/eip3540_eof_v1/container.py delete mode 100644 tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py diff --git a/src/ethereum_test_types/eof/v1/__init__.py b/src/ethereum_test_types/eof/v1/__init__.py index df29c936a9..4282e4c4df 100644 --- a/src/ethereum_test_types/eof/v1/__init__.py +++ b/src/ethereum_test_types/eof/v1/__init__.py @@ -365,6 +365,10 @@ class Container(CopyValidateModel): Body: type section first, all code sections, data section(s), last container sections """ + skip_join_concurrent_sections_in_header: bool = False + """ + Skip joining concurrent sections in the header (code and container) + """ validity_error: EOFExceptionInstanceOrList | str | None = None """ Optional error expected for the container. @@ -435,7 +439,10 @@ def bytecode(self) -> bytes: # Join headers of the same kind in a list of lists, only if they are next to each other concurrent_sections: List[List[Section]] = [[header_sections[0]]] for s in header_sections[1:]: - if s.kind == concurrent_sections[-1][-1].kind: + if ( + s.kind == concurrent_sections[-1][-1].kind + and not self.skip_join_concurrent_sections_in_header + ): concurrent_sections[-1].append(s) else: concurrent_sections.append([s]) diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/container.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/container.py deleted file mode 100644 index 1d8f146c70..0000000000 --- a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/container.py +++ /dev/null @@ -1,694 +0,0 @@ -""" -Test EVM Object Format Version 1 -""" - -from typing import List - -from ethereum_test_tools import EOFException -from ethereum_test_tools.eof.v1 import ( - VERSION_MAX_SECTION_KIND, - AutoSection, - Container, - Section, - SectionKind, -) -from ethereum_test_tools.eof.v1.constants import ( - MAX_CODE_INPUTS, - MAX_CODE_OUTPUTS, - MAX_CODE_SECTIONS, - MAX_OPERAND_STACK_HEIGHT, -) -from ethereum_test_tools.vm.opcode import Opcodes as Op - -INVALID: List[Container] = [ - Container( - name="single_code_section_no_data_section", - sections=[ - Section.Code(Op.STOP), - ], - auto_data_section=False, - validity_error=[EOFException.MISSING_DATA_SECTION, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="incomplete_magic", - raw_bytes=bytes([0xEF]), - validity_error=EOFException.INVALID_MAGIC, - ), - Container( - name="no_version", - raw_bytes=bytes([0xEF, 0x00]), - validity_error=[EOFException.INVALID_VERSION, EOFException.INVALID_MAGIC], - ), - Container( - name="no_type_header", - raw_bytes=bytes([0xEF, 0x00, 0x01]), - # TODO the exception must be about missing section types - validity_error=EOFException.MISSING_HEADERS_TERMINATOR, - ), - Container( - name="no_type_section_size", - raw_bytes=bytes( - [0xEF, 0x00, 0x01, 0x01], - ), - # TODO the exception must be about incomplete section in the header - validity_error=[ - EOFException.MISSING_HEADERS_TERMINATOR, - EOFException.INVALID_TYPE_SECTION_SIZE, - ], - ), - Container( - name="no_code_header", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0xFE]), - validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="code_section_size_incomplete_1", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02]), - validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, - ), - Container( - name="code_section_size_incomplete_2", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00]), - validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, - ), - Container( - name="code_section_size_incomplete_3", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01]), - validity_error=[EOFException.MISSING_HEADERS_TERMINATOR, EOFException.ZERO_SECTION_SIZE], - ), - Container( - name="code_section_size_incomplete_4", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0x00]), - validity_error=[EOFException.INCOMPLETE_SECTION_SIZE, EOFException.ZERO_SECTION_SIZE], - ), - Container( - name="code_section_count_0x8000_truncated", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x80, 0x00]), - validity_error=EOFException.TOO_MANY_CODE_SECTIONS, - ), - Container( - name="code_section_count_0xFFFF_truncated", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0xFF, 0xFF]), - validity_error=EOFException.TOO_MANY_CODE_SECTIONS, - ), - Container( - name="code_section_count_0x8000", - raw_bytes=bytes( - [0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x80, 0x00] + [0x00, 0x01] * 0x8000 - ), - validity_error=EOFException.CONTAINER_SIZE_ABOVE_LIMIT, - ), - Container( - name="code_section_count_0xFFFF", - raw_bytes=bytes( - [0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0xFF, 0xFF] + [0x00, 0x01] * 0xFFFF - ), - validity_error=EOFException.CONTAINER_SIZE_ABOVE_LIMIT, - ), - Container( - name="code_section_size_0x8000_truncated", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0x80, 0x00]), - validity_error=EOFException.MISSING_HEADERS_TERMINATOR, - ), - Container( - name="code_section_size_0xFFFF_truncated", - raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0xFF, 0xFF]), - validity_error=EOFException.MISSING_HEADERS_TERMINATOR, - ), - Container( - name="terminator_incomplete", - raw_bytes=bytes( - [0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0x00, 0x01, 0x04, 0x00, 0x00] - ), - validity_error=EOFException.MISSING_HEADERS_TERMINATOR, - ), - Container( - name="no_data_section_size", - raw_bytes=bytes( - [ - 0xEF, - 0x00, - 0x01, - 0x01, - 0x00, - 0x04, - 0x02, - 0x00, - 0x01, - 0x00, - 0x00, - 0x04, - ] - ), - # TODO it looks like data section is missing or section header of type 0x00 - validity_error=EOFException.ZERO_SECTION_SIZE, - ), - Container( - name="data_section_size_incomplete", - raw_bytes=bytes( - [ - 0xEF, - 0x00, - 0x01, - 0x01, - 0x00, - 0x04, - 0x02, - 0x00, - 0x01, - 0x00, - 0x00, - 0x03, - 0x00, - ] - ), - validity_error=EOFException.ZERO_SECTION_SIZE, - ), - Container( - name="no_sections", - sections=[], - auto_data_section=False, - auto_type_section=AutoSection.NONE, - expected_bytecode="ef0001 00", - validity_error=[EOFException.MISSING_TYPE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_code_section", - sections=[ - Section(kind=SectionKind.TYPE, data=bytes([0] * 4)), - Section.Data("0x00"), - ], - auto_type_section=AutoSection.NONE, - validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="too_many_code_sections", - sections=[ - Section.Code(Op.JUMPF[i + 1] if i < MAX_CODE_SECTIONS else Op.STOP) - for i in range(MAX_CODE_SECTIONS + 1) - ], - validity_error=EOFException.TOO_MANY_CODE_SECTIONS, - ), - Container( - name="zero_code_sections_header", - raw_bytes=bytes( - [ - 0xEF, - 0x00, - 0x01, - 0x01, - 0x00, - 0x04, - 0x02, - 0x00, - 0x00, - 0x03, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - ] - ), - validity_error=[EOFException.ZERO_SECTION_SIZE, EOFException.INCOMPLETE_SECTION_NUMBER], - ), - # The basic `no_section_terminator` cases just remove the terminator - # and the `00` for zeroth section inputs looks like one. Error is because - # the sections are wrongly sized. - Container( - name="no_section_terminator", - header_terminator=bytes(), - sections=[Section.Code(code=Op.STOP)], - validity_error=[ - EOFException.INVALID_SECTION_BODIES_SIZE, - EOFException.INVALID_FIRST_SECTION_TYPE, - ], - ), - Container( - name="no_section_terminator_1", - header_terminator=bytes(), - sections=[Section.Code(code=Op.STOP, custom_size=2)], - validity_error=[ - EOFException.INVALID_SECTION_BODIES_SIZE, - EOFException.INVALID_FIRST_SECTION_TYPE, - ], - ), - Container( - name="no_section_terminator_2", - header_terminator=bytes(), - sections=[Section.Code(code="0x", custom_size=3)], - validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, - ), - Container( - name="no_section_terminator_3", - header_terminator=bytes(), - sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], - validity_error=[ - EOFException.INVALID_SECTION_BODIES_SIZE, - EOFException.INVALID_FIRST_SECTION_TYPE, - ], - ), - # The following cases just remove the terminator - # and the `00` for zeroth section inputs looks like one. Section bodies - # are as the size prescribes here, so the error is about the inputs of zeroth section. - Container( - name="no_section_terminator_section_bodies_ok_1", - header_terminator=bytes(), - sections=[Section.Code(code=Op.JUMPDEST + Op.STOP, custom_size=1)], - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="no_section_terminator_section_bodies_ok_2", - header_terminator=bytes(), - sections=[Section.Code(code=Op.JUMPDEST * 2 + Op.STOP, custom_size=2)], - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - # Here the terminator is missing but made to look like a different section - # or arbitrary byte - Container( - name="no_section_terminator_nonzero", - header_terminator=b"01", - sections=[Section.Code(code=Op.STOP)], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_section_terminator_nonzero_1", - header_terminator=b"02", - sections=[Section.Code(code=Op.STOP, custom_size=2)], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_section_terminator_nonzero_2", - header_terminator=b"03", - sections=[Section.Code(code="0x", custom_size=3)], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_section_terminator_nonzero_3", - header_terminator=b"04", - sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_section_terminator_nonzero_4", - header_terminator=b"fe", - sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_code_section_contents", - sections=[Section.Code(code="0x", custom_size=0x01)], - validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, - ), - Container( - name="incomplete_code_section_contents", - sections=[ - Section.Code(code=Op.STOP, custom_size=0x02), - ], - validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, - ), - Container( - name="trailing_bytes_after_code_section", - sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], - extra=bytes([0xDE, 0xAD, 0xBE, 0xEF]), - validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, - ), - Container( - name="empty_code_section", - sections=[Section.Code(code="0x")], - # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, - validity_error=EOFException.ZERO_SECTION_SIZE, - ), - Container( - name="empty_code_section_with_non_empty_data", - sections=[ - Section.Code(code="0x"), - Section.Data(data="0xDEADBEEF"), - ], - # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, - validity_error=EOFException.ZERO_SECTION_SIZE, - ), - Container( - name="no_data_section_contents", - sections=[ - Section.Code(Op.STOP), - Section.Data(data="0x", custom_size=1), - ], - code="ef0001 010004 0200010001 040001 00 00800000 00", - validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, - ), - Container( - name="data_section_contents_incomplete", - sections=[ - Section.Code(Op.STOP), - Section.Data(data="0xAABBCC", custom_size=4), - ], - validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, - ), - Container( - name="data_section_preceding_code_section", - auto_data_section=False, - auto_sort_sections=AutoSection.NONE, - sections=[ - Section.Data(data="0xDEADBEEF"), - Section.Code(Op.STOP), - ], - validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="data_section_without_code_section", - sections=[Section.Data(data="0xDEADBEEF")], - # TODO the actual exception should be EOFException.MISSING_CODE_HEADER - validity_error=[EOFException.ZERO_SECTION_SIZE, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_section_terminator_3a", - header_terminator=bytes(), - sections=[Section.Code(code="0x030004")], - # TODO the exception must be about terminator - validity_error=[ - EOFException.INVALID_SECTION_BODIES_SIZE, - EOFException.INVALID_FIRST_SECTION_TYPE, - ], - ), - Container( - name="no_section_terminator_4a", - header_terminator=bytes(), - sections=[ - Section.Code(Op.STOP), - Section.Data(data="0xAABBCCDD"), - ], - # TODO: The error of this validation can be random. - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="trailing_bytes_after_data_section", - extra=bytes([0xEE]), - sections=[ - Section.Code(code=Op.PUSH1(0) + Op.STOP), - Section.Data(data="0xAABBCCDD"), - ], - # TODO should be more specific exception about trailing bytes - validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, - ), - Container( - name="multiple_data_sections", - sections=[ - Section.Code(code=Op.PUSH1(0) + Op.STOP), - Section.Data(data="0xAABBCC"), - Section.Data(data="0xAABBCC"), - ], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="multiple_code_and_data_sections", - sections=[ - Section.Code(Op.STOP), - Section.Code(Op.STOP), - Section.Data(data="0xAA"), - Section.Data(data="0xAA"), - ], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="unknown_section_1", - sections=[ - Section.Code(Op.STOP), - Section.Data(data="0x"), - Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x01"), - ], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="unknown_section_2", - sections=[ - Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x01"), - Section.Data(data="0x"), - Section.Code(Op.STOP), - ], - # TODO the exception should be about unknown section definition - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="unknown_section_empty", - sections=[ - Section.Code(Op.STOP), - Section.Data(data="0x"), - Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x"), - ], - validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="no_type_section", - sections=[ - Section.Code(code=Op.STOP), - Section.Data("0x00"), - ], - auto_type_section=AutoSection.NONE, - validity_error=[EOFException.MISSING_TYPE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="too_many_type_sections", - sections=[ - Section(kind=SectionKind.TYPE, data="0x00000000"), - Section(kind=SectionKind.TYPE, data="0x00000000"), - Section.Code(Op.STOP), - ], - auto_type_section=AutoSection.NONE, - validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="empty_type_section", - sections=[ - Section(kind=SectionKind.TYPE, data="0x"), - Section.Code(Op.STOP), - ], - auto_type_section=AutoSection.NONE, - # TODO the exception must be about type section EOFException.INVALID_TYPE_SECTION_SIZE, - validity_error=[EOFException.ZERO_SECTION_SIZE, EOFException.INVALID_SECTION_BODIES_SIZE], - ), - Container( - name="type_section_too_small_1", - sections=[ - Section(kind=SectionKind.TYPE, data="0x00"), - Section.Code(Op.STOP), - ], - auto_type_section=AutoSection.NONE, - validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, - ), - Container( - name="type_section_too_small_2", - sections=[ - Section(kind=SectionKind.TYPE, data="0x000000"), - Section.Code(Op.STOP), - ], - auto_type_section=AutoSection.NONE, - validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, - ), - Container( - name="type_section_too_big", - sections=[ - Section(kind=SectionKind.TYPE, data="0x0000000000"), - Section.Code(Op.STOP), - ], - auto_type_section=AutoSection.NONE, - validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, - ), -] - -# TODO: Max initcode as specified on EIP-3860 - -""" -EIP-4750 Valid and Invalid Containers -""" - -VALID = [ - Container( - name="single_code_section_max_stack_size", - sections=[ - Section.Code( - code=(Op.CALLER * MAX_OPERAND_STACK_HEIGHT) - + (Op.POP * MAX_OPERAND_STACK_HEIGHT) - + Op.STOP, - max_stack_height=MAX_OPERAND_STACK_HEIGHT, - ), - ], - ), - Container( - name="single_code_section_input_maximum", - sections=[ - Section.Code( - code=((Op.PUSH0 * MAX_CODE_INPUTS) + Op.CALLF[1] + Op.STOP), - max_stack_height=MAX_CODE_INPUTS, - ), - Section.Code( - code=(Op.POP * MAX_CODE_INPUTS) + Op.RETF, - code_inputs=MAX_CODE_INPUTS, - code_outputs=0, - max_stack_height=MAX_CODE_INPUTS, - ), - ], - ), - Container( - name="single_code_section_output_maximum", - sections=[ - Section.Code( - code=(Op.CALLF[1] + Op.STOP), - max_stack_height=MAX_CODE_OUTPUTS, - ), - Section.Code( - code=(Op.PUSH0 * MAX_CODE_OUTPUTS) + Op.RETF, - code_inputs=0, - code_outputs=MAX_CODE_OUTPUTS, - max_stack_height=MAX_CODE_OUTPUTS, - ), - ], - ), - Container( - name="multiple_code_section_max_inputs_max_outputs", - sections=[ - Section.Code( - (Op.PUSH0 * MAX_CODE_OUTPUTS) + Op.CALLF[1] + Op.STOP, - max_stack_height=MAX_CODE_OUTPUTS, - ), - Section.Code( - code=Op.RETF, - code_inputs=MAX_CODE_INPUTS, - code_outputs=MAX_CODE_OUTPUTS, - max_stack_height=MAX_CODE_INPUTS, - ), - ], - ), -] - -INVALID += [ - Container( - name="single_code_section_non_zero_inputs", - sections=[Section.Code(code=Op.POP + Op.RETF, code_inputs=1)], - # TODO the exception must be about code or non, cause it looks legit - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="single_code_section_non_zero_outputs", - sections=[Section.Code(code=Op.PUSH0 + Op.RETF, code_outputs=1)], - # TODO the exception must be about code or non, cause it looks legit - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="multiple_code_section_non_zero_inputs", - sections=[ - Section.Code(code=Op.POP + Op.RETF, code_inputs=1), - Section.Code(Op.STOP), - ], - # TODO the actual exception should be EOFException.INVALID_TYPE_BODY, - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="multiple_code_section_non_zero_outputs", - sections=[ - Section.Code(code=Op.PUSH0, code_outputs=1), - Section.Code(Op.STOP), - ], - # TODO the actual exception should be EOFException.INVALID_TYPE_BODY, - validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, - ), - Container( - name="data_section_before_code_with_type", - sections=[ - Section.Data(data="0xAA"), - Section.Code(Op.STOP), - ], - auto_sort_sections=AutoSection.NONE, - validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], - ), - Container( - name="data_section_listed_in_type", - sections=[ - Section.Data(data="0x00", force_type_listing=True), - Section.Code(Op.STOP), - ], - validity_error=[ - EOFException.INVALID_TYPE_SECTION_SIZE, - EOFException.INVALID_SECTION_BODIES_SIZE, - ], - ), - Container( - name="single_code_section_incomplete_type", - sections=[ - Section(kind=SectionKind.TYPE, data="0x00", custom_size=2), - Section.Code(Op.STOP), - ], - validity_error=[ - EOFException.INVALID_SECTION_BODIES_SIZE, - EOFException.INVALID_TYPE_SECTION_SIZE, - ], - ), - Container( - name="single_code_section_input_too_large", - sections=[ - Section.Code( - code=((Op.PUSH0 * (MAX_CODE_INPUTS + 1)) + Op.CALLF[1] + Op.STOP), - max_stack_height=(MAX_CODE_INPUTS + 1), - ), - Section.Code( - code=(Op.POP * (MAX_CODE_INPUTS + 1)) + Op.RETF, - code_inputs=(MAX_CODE_INPUTS + 1), - code_outputs=0, - max_stack_height=0, - ), - ], - # TODO auto types section generation probably failed. the exception must be about code - validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, - ), - Container( - name="invalid_inputs_to_non_returning_code_section_2", - sections=[ - Section.Code( - code=Op.PUSH1(0) * 128 + Op.CALLF[1] + Op.STOP, - max_stack_height=128, - ), - Section.Code( - Op.STOP, - code_inputs=128, - code_outputs=0, - max_stack_height=128, - ), - ], - # TODO auto types section generation probably failed. the exception must be about code - validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, - ), - Container( - name="single_code_section_output_too_large", - sections=[ - Section.Code( - code=(Op.CALLF[1] + Op.STOP), - max_stack_height=(MAX_CODE_OUTPUTS + 2), - ), - Section.Code( - code=(Op.PUSH0 * (MAX_CODE_OUTPUTS + 2)) + Op.RETF, - code_inputs=0, - code_outputs=(MAX_CODE_OUTPUTS + 2), - max_stack_height=(MAX_CODE_OUTPUTS + 1), - ), - ], - # TODO the exception must be about code body - validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, - ), - Container( - name="single_code_section_max_stack_size_too_large", - sections=[ - Section.Code( - code=Op.CALLER * 1024 + Op.POP * 1024 + Op.STOP, - max_stack_height=1024, - ), - ], - # TODO auto types section generation probably failed, the exception must be about code - validity_error=EOFException.MAX_STACK_HEIGHT_ABOVE_LIMIT, - ), -] diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py deleted file mode 100644 index 3af9e07cc9..0000000000 --- a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_code_validation.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -EOF V1 Code Validation tests -""" - -import pytest - -from ethereum_test_tools import EOFTestFiller -from ethereum_test_tools.eof.v1 import Container - -from .. import EOF_FORK_NAME -from .container import INVALID, VALID - -REFERENCE_SPEC_GIT_PATH = "EIPS/eip-3540.md" -REFERENCE_SPEC_VERSION = "8dcb0a8c1c0102c87224308028632cc986a61183" - -pytestmark = pytest.mark.valid_from(EOF_FORK_NAME) - - -def container_name(c: Container): - """ - Return the name of the container for use in pytest ids. - """ - if hasattr(c, "name"): - return c.name - else: - return c.__class__.__name__ - - -@pytest.mark.parametrize( - "container", - VALID, - ids=container_name, -) -def test_legacy_initcode_valid_eof_v1_contract( - eof_test: EOFTestFiller, - container: Container, -): - """ - Test creating various types of valid EOF V1 contracts using legacy - initcode and a contract creating transaction. - """ - assert ( - container.validity_error is None - ), f"Valid container with validity error: {container.validity_error}" - eof_test( - data=bytes(container), - ) - - -@pytest.mark.parametrize( - "container", - INVALID, - ids=container_name, -) -def test_legacy_initcode_invalid_eof_v1_contract( - eof_test: EOFTestFiller, - container: Container, -): - """ - Test creating various types of valid EOF V1 contracts using legacy - initcode and a contract creating transaction. - """ - assert container.validity_error is not None, "Invalid container without validity error" - eof_test( - data=bytes(container), - expect_exception=container.validity_error, - ) diff --git a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py index 3bb3424689..0cae0db27c 100644 --- a/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py +++ b/tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py @@ -6,9 +6,21 @@ import pytest from ethereum_test_tools import EOFException, EOFTestFiller -from ethereum_test_tools import Opcodes as Op -from ethereum_test_tools.eof.v1 import Container, ContainerKind, Section -from ethereum_test_tools.eof.v1.constants import MAX_CODE_SECTIONS +from ethereum_test_tools.eof.v1 import ( + VERSION_MAX_SECTION_KIND, + AutoSection, + Container, + ContainerKind, + Section, + SectionKind, +) +from ethereum_test_tools.eof.v1.constants import ( + MAX_CODE_INPUTS, + MAX_CODE_OUTPUTS, + MAX_CODE_SECTIONS, + MAX_OPERAND_STACK_HEIGHT, +) +from ethereum_test_tools.vm.opcode import Opcodes as Op from .. import EOF_FORK_NAME @@ -20,6 +32,1077 @@ VALID_CONTAINER = Container(sections=[Section.Code(code=Op.STOP)]) +@pytest.mark.parametrize( + "container", + [ + Container( + name="single_code_section_with_data_section", + sections=[ + Section.Code(code=Op.STOP), + Section.Data(data="0x00"), + ], + ), + Container( + name="single_code_section_max_stack_size", + sections=[ + Section.Code( + code=(Op.CALLER * MAX_OPERAND_STACK_HEIGHT) + + (Op.POP * MAX_OPERAND_STACK_HEIGHT) + + Op.STOP, + max_stack_height=MAX_OPERAND_STACK_HEIGHT, + ), + ], + ), + Container( + name="code_section_with_inputs_outputs", + sections=[ + Section.Code( + code=(Op.PUSH0 + Op.CALLF[1] + Op.STOP), + ), + Section.Code( + code=Op.POP + Op.PUSH0 + Op.RETF, + code_inputs=1, + code_outputs=1, + ), + ], + ), + Container( + name="code_section_input_maximum", + sections=[ + Section.Code( + code=((Op.PUSH0 * MAX_CODE_INPUTS) + Op.CALLF[1] + Op.STOP), + max_stack_height=MAX_CODE_INPUTS, + ), + Section.Code( + code=(Op.POP * MAX_CODE_INPUTS) + Op.RETF, + code_inputs=MAX_CODE_INPUTS, + code_outputs=0, + max_stack_height=MAX_CODE_INPUTS, + ), + ], + ), + Container( + name="code_section_output_maximum", + sections=[ + Section.Code( + code=(Op.CALLF[1] + Op.STOP), + max_stack_height=MAX_CODE_OUTPUTS, + ), + Section.Code( + code=(Op.PUSH0 * MAX_CODE_OUTPUTS) + Op.RETF, + code_inputs=0, + code_outputs=MAX_CODE_OUTPUTS, + max_stack_height=MAX_CODE_OUTPUTS, + ), + ], + ), + Container( + name="multiple_code_sections", + sections=[ + Section.Code( + Op.CALLF[1] + Op.STOP, + ), + Section.Code( + code=Op.RETF, + code_inputs=0, + code_outputs=0, + ), + ], + ), + Container( + name="multiple_code_sections_max_inputs_max_outputs", + sections=[ + Section.Code( + (Op.PUSH0 * MAX_CODE_OUTPUTS) + Op.CALLF[1] + Op.STOP, + max_stack_height=MAX_CODE_OUTPUTS, + ), + Section.Code( + code=Op.RETF, + code_inputs=MAX_CODE_INPUTS, + code_outputs=MAX_CODE_OUTPUTS, + max_stack_height=MAX_CODE_INPUTS, + ), + ], + ), + Container( + name="single_subcontainer_without_data", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section.Container(Container.Code(Op.INVALID)), + ], + ), + Container( + name="single_subcontainer_with_data", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section.Container(Container.Code(Op.INVALID)), + Section.Data(data="0xAA"), + ], + ), + ], + ids=lambda c: c.name, +) +def test_valid_containers( + eof_test: EOFTestFiller, + container: Container, +): + """ + Test creating various types of valid EOF V1 contracts using legacy + initcode and a contract creating transaction. + """ + assert ( + container.validity_error is None + ), f"Valid container with validity error: {container.validity_error}" + eof_test( + data=bytes(container), + ) + + +@pytest.mark.parametrize( + "container", + [ + Container( + name="empty_container", + raw_bytes=b"", + validity_error=[ + EOFException.INVALID_MAGIC, + ], + ), + Container( + name="single_code_section_no_data_section", + sections=[ + Section.Code(Op.STOP), + ], + auto_data_section=False, + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="incomplete_magic", + raw_bytes=bytes([0xEF]), + validity_error=EOFException.INVALID_MAGIC, + ), + Container( + name="no_version", + raw_bytes=bytes([0xEF, 0x00]), + validity_error=[EOFException.INVALID_VERSION, EOFException.INVALID_MAGIC], + ), + Container( + name="no_type_header", + raw_bytes=bytes([0xEF, 0x00, 0x01]), + # TODO the exception must be about missing section types + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="no_type_section_size", + raw_bytes=bytes( + [0xEF, 0x00, 0x01, 0x01], + ), + # TODO the exception must be about incomplete section in the header + validity_error=[ + EOFException.MISSING_HEADERS_TERMINATOR, + EOFException.INVALID_TYPE_SECTION_SIZE, + ], + ), + Container( + name="incomplete_type_section_size", + raw_bytes=bytes( + [0xEF, 0x00, 0x01, 0x01, 0x00], + ), + # TODO the exception must be about incomplete section in the header + validity_error=[ + EOFException.INCOMPLETE_SECTION_SIZE, + EOFException.INVALID_TYPE_SECTION_SIZE, + ], + ), + Container( + name="no_code_header", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04]), + validity_error=[ + EOFException.MISSING_CODE_HEADER, + EOFException.MISSING_HEADERS_TERMINATOR, + ], + ), + Container( + name="no_code_header_2", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0xFE]), + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_code_header_3", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x00]), + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="code_section_count_missing", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02]), + validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, + ), + Container( + name="code_section_count_incomplete", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00]), + validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, + ), + Container( + name="code_section_size_missing", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01]), + validity_error=[ + EOFException.MISSING_HEADERS_TERMINATOR, + EOFException.ZERO_SECTION_SIZE, + ], + ), + Container( + name="code_section_size_incomplete", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0x00]), + validity_error=[EOFException.INCOMPLETE_SECTION_SIZE, EOFException.ZERO_SECTION_SIZE], + ), + Container( + name="code_section_count_0x8000_truncated", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x80, 0x00]), + validity_error=EOFException.TOO_MANY_CODE_SECTIONS, + ), + Container( + name="code_section_count_0xFFFF_truncated", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0xFF, 0xFF]), + validity_error=EOFException.TOO_MANY_CODE_SECTIONS, + ), + Container( + name="code_section_count_0x8000", + raw_bytes=bytes( + [0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x80, 0x00] + [0x00, 0x01] * 0x8000 + ), + validity_error=EOFException.CONTAINER_SIZE_ABOVE_LIMIT, + ), + Container( + name="code_section_count_0xFFFF", + raw_bytes=bytes( + [0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0xFF, 0xFF] + [0x00, 0x01] * 0xFFFF + ), + validity_error=EOFException.CONTAINER_SIZE_ABOVE_LIMIT, + ), + Container( + name="code_section_size_0x8000_truncated", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0x80, 0x00]), + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="code_section_size_0xFFFF_truncated", + raw_bytes=bytes([0xEF, 0x00, 0x01, 0x01, 0x00, 0x04, 0x02, 0x00, 0x01, 0xFF, 0xFF]), + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="terminator_incomplete", + header_terminator=b"", + sections=[ + Section(kind=SectionKind.TYPE, data=b"", custom_size=4), + Section.Code(code=b"", custom_size=0x01), + ], + expected_bytecode="ef00 01 01 0004 02 0001 0001 04 0000", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="truncated_header_data_section", + raw_bytes="ef00 01 01 0004 02 0001 0001", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="no_data_section_size", + raw_bytes="ef00 01 01 0004 02 0001 0001 04", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="data_section_size_incomplete", + raw_bytes="ef00 01 01 0004 02 0001 0001 04 00", + validity_error=EOFException.INCOMPLETE_SECTION_SIZE, + ), + Container( + name="no_container_section_count", + raw_bytes="ef00 01 01 0004 02 0001 0001 03", + validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, + ), + Container( + name="incomplete_container_section_count", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 00", + validity_error=EOFException.INCOMPLETE_SECTION_NUMBER, + ), + Container( + name="zero_container_section_count", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0000 04 0000 00 00800000 00", + validity_error=EOFException.ZERO_SECTION_SIZE, + ), + Container( + name="no_container_section_size", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="incomplete_container_section_size", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 00", + validity_error=EOFException.INCOMPLETE_SECTION_SIZE, + ), + Container( + name="incomplete_container_section_size_2", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0002 0001", + validity_error=EOFException.INCOMPLETE_SECTION_SIZE, + ), + Container( + name="incomplete_container_section_size_3", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0002 0001 00", + validity_error=EOFException.INCOMPLETE_SECTION_SIZE, + ), + Container( + name="zero_size_container_section", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 0000 04 0000 00 00800000 00", + validity_error=EOFException.ZERO_SECTION_SIZE, + ), + Container( + name="truncated_header_data_section_with_container_section", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 0001", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="no_data_section_size_with_container_section", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 0001 04", + validity_error=EOFException.MISSING_HEADERS_TERMINATOR, + ), + Container( + name="data_section_size_incomplete_with_container_section", + raw_bytes="ef00 01 01 0004 02 0001 0001 03 0001 0001 04 00", + validity_error=EOFException.INCOMPLETE_SECTION_SIZE, + ), + Container( + name="no_sections", + sections=[], + auto_data_section=False, + auto_type_section=AutoSection.NONE, + expected_bytecode="ef0001 00", + validity_error=[EOFException.MISSING_TYPE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_code_section_header", + sections=[ + Section(kind=SectionKind.TYPE, data=b"\0\x80\0\0"), + Section.Data("0x00"), + ], + expected_bytecode="ef00 01 01 0004 04 0001 00 00800000 00", + auto_type_section=AutoSection.NONE, + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="too_many_code_sections", + sections=[ + Section.Code(Op.JUMPF[i + 1] if i < MAX_CODE_SECTIONS else Op.STOP) + for i in range(MAX_CODE_SECTIONS + 1) + ], + validity_error=EOFException.TOO_MANY_CODE_SECTIONS, + ), + Container( + name="zero_code_sections_header", + raw_bytes="ef00 01 01 0004 02 0000 04 0000 00 00800000", + validity_error=[ + EOFException.ZERO_SECTION_SIZE, + EOFException.INCOMPLETE_SECTION_NUMBER, + ], + ), + Container( + name="zero_code_sections_header_empty_type_section", + raw_bytes="ef00 01 01 0000 02 0000 04 0000 00", + validity_error=[ + EOFException.ZERO_SECTION_SIZE, + EOFException.INCOMPLETE_SECTION_NUMBER, + ], + ), + # The basic `no_section_terminator` cases just remove the terminator + # and the `00` for zeroth section inputs looks like one. Error is because + # the sections are wrongly sized. + Container( + name="no_section_terminator", + header_terminator=bytes(), + sections=[Section.Code(code=Op.STOP)], + validity_error=[ + EOFException.INVALID_SECTION_BODIES_SIZE, + EOFException.INVALID_FIRST_SECTION_TYPE, + ], + ), + Container( + name="no_section_terminator_1", + header_terminator=bytes(), + sections=[Section.Code(code=Op.STOP, custom_size=2)], + validity_error=[ + EOFException.INVALID_SECTION_BODIES_SIZE, + EOFException.INVALID_FIRST_SECTION_TYPE, + ], + ), + Container( + name="no_section_terminator_2", + header_terminator=bytes(), + sections=[Section.Code(code="0x", custom_size=3)], + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="no_section_terminator_3", + header_terminator=bytes(), + sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], + validity_error=[ + EOFException.INVALID_SECTION_BODIES_SIZE, + EOFException.INVALID_FIRST_SECTION_TYPE, + ], + ), + # The following cases just remove the terminator + # and the `00` for zeroth section inputs looks like one. Section bodies + # are as the size prescribes here, so the error is about the inputs of zeroth section. + Container( + name="no_section_terminator_section_bodies_ok_1", + header_terminator=bytes(), + sections=[Section.Code(code=Op.JUMPDEST + Op.STOP, custom_size=1)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="no_section_terminator_section_bodies_ok_2", + header_terminator=bytes(), + sections=[Section.Code(code=Op.JUMPDEST * 2 + Op.STOP, custom_size=2)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + # Here the terminator is missing but made to look like a different section + # or arbitrary byte + Container( + name="no_section_terminator_nonzero", + header_terminator=b"01", + sections=[Section.Code(code=Op.STOP)], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_section_terminator_nonzero_1", + header_terminator=b"02", + sections=[Section.Code(code=Op.STOP, custom_size=2)], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_section_terminator_nonzero_2", + header_terminator=b"03", + sections=[Section.Code(code="0x", custom_size=3)], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_section_terminator_nonzero_3", + header_terminator=b"04", + sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_section_terminator_nonzero_4", + header_terminator=b"fe", + sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="truncated_before_type_section", + sections=[ + Section(kind=SectionKind.TYPE, data=b"", custom_size=4), + Section.Code(code=b"", custom_size=0x01), + ], + expected_bytecode="ef00 01 01 0004 02 0001 0001 04 0000 00", + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="truncated_type_section_before_outputs", + sections=[ + Section(kind=SectionKind.TYPE, data=b"\0", custom_size=4), + Section.Code(code=b"", custom_size=0x01), + ], + expected_bytecode="ef00 01 01 0004 02 0001 0001 04 0000 00 00", + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="truncated_type_section_before_max_stack_height", + sections=[ + Section(kind=SectionKind.TYPE, data=b"\0\x80", custom_size=4), + Section.Code(code=b"", custom_size=0x01), + ], + expected_bytecode="ef00 01 01 0004 02 0001 0001 04 0000 00 0080", + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="truncated_type_section_truncated_max_stack_height", + sections=[ + Section(kind=SectionKind.TYPE, data=b"\0\x80\0", custom_size=4), + Section.Code(code=b"", custom_size=0x01), + ], + expected_bytecode="ef00 01 01 0004 02 0001 0001 04 0000 00 008000", + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="no_code_section_contents", + sections=[Section.Code(code="0x", custom_size=0x01)], + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="incomplete_code_section_contents", + sections=[ + Section.Code(code=Op.STOP, custom_size=0x02), + ], + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="trailing_bytes_after_code_section", + sections=[Section.Code(code=Op.PUSH1(0) + Op.STOP)], + extra=bytes([0xDE, 0xAD, 0xBE, 0xEF]), + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="empty_code_section", + sections=[Section.Code(code="0x")], + # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, + validity_error=EOFException.ZERO_SECTION_SIZE, + ), + Container( + name="empty_code_section_with_non_empty_data", + sections=[ + Section.Code(code="0x"), + Section.Data(data="0xDEADBEEF"), + ], + # TODO the exception must be about code section EOFException.INVALID_CODE_SECTION, + validity_error=EOFException.ZERO_SECTION_SIZE, + ), + Container( + name="no_container_section_contents", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section(kind=SectionKind.CONTAINER, data=b"", custom_size=20), + ], + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="no_container_section_contents_with_data", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section(kind=SectionKind.CONTAINER, data=b"", custom_size=20), + Section.Data(b"\0" * 20), + ], + validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, + ), + Container( + name="no_data_section_contents", + sections=[ + Section.Code(Op.STOP), + Section.Data(data="0x", custom_size=1), + ], + code="ef0001 010004 0200010001 040001 00 00800000 00", + validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, + ), + Container( + name="data_section_contents_incomplete", + sections=[ + Section.Code(Op.STOP), + Section.Data(data="0xAABBCC", custom_size=4), + ], + validity_error=EOFException.TOPLEVEL_CONTAINER_TRUNCATED, + ), + Container( + name="data_section_preceding_code_section", + auto_data_section=False, + auto_sort_sections=AutoSection.NONE, + sections=[ + Section.Data(data="0xDEADBEEF"), + Section.Code(Op.STOP), + ], + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="data_section_without_code_section", + sections=[Section.Data(data="0xDEADBEEF")], + # TODO the actual exception should be EOFException.MISSING_CODE_HEADER + validity_error=[EOFException.ZERO_SECTION_SIZE, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_section_terminator_3a", + header_terminator=bytes(), + sections=[Section.Code(code="0x030004")], + # TODO the exception must be about terminator + validity_error=[ + EOFException.INVALID_SECTION_BODIES_SIZE, + EOFException.INVALID_FIRST_SECTION_TYPE, + ], + ), + Container( + name="no_section_terminator_4a", + header_terminator=bytes(), + sections=[ + Section.Code(Op.STOP), + Section.Data(data="0xAABBCCDD"), + ], + # TODO: The error of this validation can be random. + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="trailing_bytes_after_data_section", + extra=bytes([0xEE]), + sections=[ + Section.Code(code=Op.PUSH1(0) + Op.STOP), + Section.Data(data="0xAABBCCDD"), + ], + # TODO should be more specific exception about trailing bytes + validity_error=EOFException.INVALID_SECTION_BODIES_SIZE, + ), + Container( + name="multiple_data_sections", + sections=[ + Section.Code(code=Op.PUSH1(0) + Op.STOP), + Section.Data(data="0xAABBCC"), + Section.Data(data="0xAABBCC"), + ], + expected_bytecode=( + "ef00 01 01 0004 02 0001 0003 04 0003 04 0003 00 00800001 600000 AABBCC AABBCC" + ), + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="multiple_code_headers", + sections=[ + Section.Code(Op.JUMPF[1]), + Section.Data(data="0xAA"), + Section.Code(Op.STOP), + ], + auto_sort_sections=AutoSection.ONLY_BODY, + expected_bytecode=( + "ef00 01 01 0008 02 0001 0003 04 0001 02 0001 0001 00" + "00800000 00800000 E50001 00 AA" + ), + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="multiple_code_headers_2", + sections=[ + Section.Code(Op.JUMPF[1]), + Section.Code(Op.STOP), + Section.Data(data="0xAA"), + ], + skip_join_concurrent_sections_in_header=True, + expected_bytecode=( + "ef00 01 01 0008 02 0001 0003 02 0001 0001 04 0001 00" + "00800000 00800000 E50001 00 AA" + ), + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="duplicated_code_header", + sections=[ + Section.Code(Op.STOP), + Section.Code( + b"", + custom_size=1, + skip_types_header_listing=True, + skip_types_body_listing=True, + ), + Section.Data(data="0xAA"), + ], + skip_join_concurrent_sections_in_header=True, + expected_bytecode=( + "ef00 01 01 0004 02 0001 0001 02 0001 0001 04 0001 00 00800000 00 AA" + ), + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="multiple_code_and_data_sections", + sections=[ + Section.Code(Op.JUMPF[1]), + Section.Code(Op.STOP), + Section.Data(data="0xAA"), + Section.Data(data="0xAA"), + ], + expected_bytecode=( + "ef00 01 01 0008 02 0002 0003 0001 04 0001 04 0001 00" + "00800000 00800000 E50001 00 AA AA" + ), + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="multiple_code_and_data_sections_2", + sections=[ + Section.Code(Op.JUMPF[1]), + Section.Code(Op.STOP), + Section.Data(data="0xAA"), + Section.Data(data="0xAA"), + ], + skip_join_concurrent_sections_in_header=True, + expected_bytecode=( + "ef00 01 01 0008 02 0001 0003 02 0001 0001 04 0001 04 0001 00" + "00800000 00800000 E50001 00 AA AA" + ), + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="multiple_container_headers", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.EOFCREATE[1](0, 0, 0, 0) + Op.STOP), + Section.Container(Container.Code(code=Op.INVALID)), + Section.Data(data="0xAA"), + Section.Container(Container.Code(code=Op.INVALID)), + ], + auto_sort_sections=AutoSection.ONLY_BODY, + expected_bytecode=( + "ef00 01 01 0004 02 0001 0015 03 0001 0014 04 0001 03 0001 0014 00" + "00800005 6000600060006000ec00 6000600060006000ec01 00" + "ef00 01 01 0004 02 0001 0001 04 0000 00 00800000 fe" + "ef00 01 01 0004 02 0001 0001 04 0000 00 00800000 fe" + "aa" + ), + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="multiple_container_headers_2", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.EOFCREATE[1](0, 0, 0, 0) + Op.STOP), + Section.Container(Container.Code(code=Op.INVALID)), + Section.Container(Container.Code(code=Op.INVALID)), + Section.Data(data="0xAA"), + ], + skip_join_concurrent_sections_in_header=True, + expected_bytecode=( + "ef00 01 01 0004 02 0001 0015 03 0001 0014 03 0001 0014 04 0001 00" + "00800005 6000600060006000ec00 6000600060006000ec01 00" + "ef00 01 01 0004 02 0001 0001 04 0000 00 00800000 fe" + "ef00 01 01 0004 02 0001 0001 04 0000 00 00800000 fe" + "aa" + ), + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="duplicated_container_header", + sections=[ + Section.Code(Op.EOFCREATE[0](0, 0, 0, 0) + Op.STOP), + Section.Container(Container.Code(code=Op.INVALID)), + Section(kind=SectionKind.CONTAINER, data=b"", custom_size=20), + Section.Data(data="0xAA"), + ], + skip_join_concurrent_sections_in_header=True, + expected_bytecode=( + "ef00 01 01 0004 02 0001 000b 03 0001 0014 03 0001 0014 04 0001 00" + "00800004 6000600060006000ec00 00" + "ef00 01 01 0004 02 0001 0001 04 0000 00 00800000 fe" + "aa" + ), + validity_error=[ + EOFException.MISSING_DATA_SECTION, + EOFException.UNEXPECTED_HEADER_KIND, + ], + ), + Container( + name="unknown_section_1", + sections=[ + Section.Code(Op.STOP), + Section.Data(data="0x"), + Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x01"), + ], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="unknown_section_2", + sections=[ + Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x01"), + Section.Data(data="0x"), + Section.Code(Op.STOP), + ], + # TODO the exception should be about unknown section definition + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="unknown_section_empty", + sections=[ + Section.Code(Op.STOP), + Section.Data(data="0x"), + Section(kind=VERSION_MAX_SECTION_KIND + 1, data="0x"), + ], + validity_error=[EOFException.MISSING_TERMINATOR, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="no_type_section", + sections=[ + Section.Code(code=Op.STOP), + Section.Data("0x00"), + ], + auto_type_section=AutoSection.NONE, + validity_error=[EOFException.MISSING_TYPE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="too_many_type_sections", + sections=[ + Section(kind=SectionKind.TYPE, data="0x00000000"), + Section(kind=SectionKind.TYPE, data="0x00000000"), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="too_many_type_sections_2", + sections=[ + Section(kind=SectionKind.TYPE, data="0x00800000"), + Section(kind=SectionKind.TYPE, data="0x00800000"), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="empty_type_section", + sections=[ + Section(kind=SectionKind.TYPE, data="0x"), + Section.Code(Op.STOP), + ], + expected_bytecode="ef00 01 01 0000 02 0001 0001 04 0000 00 00", + validity_error=[ + EOFException.ZERO_SECTION_SIZE, + EOFException.INVALID_SECTION_BODIES_SIZE, + ], + ), + Container( + name="type_section_too_small_single_code_section_1", + sections=[ + Section(kind=SectionKind.TYPE, data="0x00"), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="type_section_too_small_single_code_section_2", + sections=[ + Section(kind=SectionKind.TYPE, data="0x008000"), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="type_section_too_big_single_code_section", + sections=[ + Section(kind=SectionKind.TYPE, data="0x0080000000"), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="type_section_too_small_multiple_code_sections_1", + sections=[ + Section(kind=SectionKind.TYPE, data="0x0080000000"), + Section.Code(Op.STOP), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="type_section_too_small_multiple_code_sections_2", + sections=[ + Section(kind=SectionKind.TYPE, data="0x008000000080"), + Section.Code(Op.STOP), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="type_section_too_big_multiple_code_sections", + sections=[ + Section(kind=SectionKind.TYPE, data="0x008000000080000000"), + Section.Code(Op.STOP), + Section.Code(Op.STOP), + ], + auto_type_section=AutoSection.NONE, + validity_error=EOFException.INVALID_TYPE_SECTION_SIZE, + ), + Container( + name="invalid_first_code_section_inputs_0x01", + sections=[Section.Code(code=Op.POP + Op.RETF, code_inputs=1)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_inputs_0x80", + sections=[Section.Code(code=Op.POP + Op.RETF, code_inputs=0x80)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_inputs_0xff", + sections=[Section.Code(code=Op.POP + Op.RETF, code_inputs=0xFF)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_outputs_0x00", + sections=[Section.Code(code=Op.PUSH0 + Op.RETF, code_outputs=0)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_outputs_0x7f", + sections=[Section.Code(code=Op.PUSH0 + Op.RETF, code_outputs=0x7F)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_outputs_0x81", + sections=[Section.Code(code=Op.PUSH0 + Op.RETF, code_outputs=0x81)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="invalid_first_code_section_outputs_0xff", + sections=[Section.Code(code=Op.PUSH0 + Op.RETF, code_outputs=0xFF)], + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="multiple_code_section_non_zero_inputs", + sections=[ + Section.Code(code=Op.POP + Op.RETF, code_inputs=1), + Section.Code(Op.STOP), + ], + # TODO the actual exception should be EOFException.INVALID_TYPE_BODY, + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="multiple_code_section_non_zero_outputs", + sections=[ + Section.Code(code=Op.PUSH0, code_outputs=1), + Section.Code(Op.STOP), + ], + # TODO the actual exception should be EOFException.INVALID_TYPE_BODY, + validity_error=EOFException.INVALID_FIRST_SECTION_TYPE, + ), + Container( + name="data_section_before_code_with_type", + sections=[ + Section.Data(data="0xAA"), + Section.Code(Op.STOP), + ], + auto_sort_sections=AutoSection.NONE, + validity_error=[EOFException.MISSING_CODE_HEADER, EOFException.UNEXPECTED_HEADER_KIND], + ), + Container( + name="data_section_listed_in_type", + sections=[ + Section.Data(data="0x00", force_type_listing=True), + Section.Code(Op.STOP), + ], + validity_error=[ + EOFException.INVALID_TYPE_SECTION_SIZE, + EOFException.INVALID_SECTION_BODIES_SIZE, + ], + ), + Container( + name="single_code_section_incomplete_type", + sections=[ + Section(kind=SectionKind.TYPE, data="0x00", custom_size=2), + Section.Code(Op.STOP), + ], + validity_error=[ + EOFException.INVALID_SECTION_BODIES_SIZE, + EOFException.INVALID_TYPE_SECTION_SIZE, + ], + ), + Container( + name="code_section_input_too_large", + sections=[ + Section.Code( + code=((Op.PUSH0 * (MAX_CODE_INPUTS + 1)) + Op.CALLF[1] + Op.STOP), + max_stack_height=(MAX_CODE_INPUTS + 1), + ), + Section.Code( + code=(Op.POP * (MAX_CODE_INPUTS + 1)) + Op.RETF, + code_inputs=(MAX_CODE_INPUTS + 1), + code_outputs=0, + max_stack_height=0, + ), + ], + validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, + ), + Container( + name="invalid_inputs_to_non_returning_code_section_2", + sections=[ + Section.Code( + code=Op.PUSH1(0) * 128 + Op.CALLF[1] + Op.STOP, + max_stack_height=128, + ), + Section.Code( + Op.STOP, + code_inputs=128, + code_outputs=0, + max_stack_height=128, + ), + ], + validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, + ), + Container( + name="code_section_output_too_large", + sections=[ + Section.Code( + code=(Op.CALLF[1] + Op.STOP), + max_stack_height=(MAX_CODE_OUTPUTS + 2), + ), + Section.Code( + code=(Op.PUSH0 * (MAX_CODE_OUTPUTS + 2)) + Op.RETF, + code_inputs=0, + code_outputs=(MAX_CODE_OUTPUTS + 2), + max_stack_height=(MAX_CODE_OUTPUTS + 2), + ), + ], + validity_error=EOFException.INPUTS_OUTPUTS_NUM_ABOVE_LIMIT, + ), + Container( + name="code_section_output_too_large_2", + sections=[ + Section.Code( + code=Op.JUMPF[1], + ), + Section.Code( + code=(Op.PUSH0 * (MAX_CODE_OUTPUTS + 1)) + Op.RETF, + code_inputs=0, + code_outputs=(MAX_CODE_OUTPUTS + 1), + max_stack_height=(MAX_CODE_OUTPUTS + 1), + ), + ], + validity_error=EOFException.INVALID_NON_RETURNING_FLAG, + ), + Container( + name="single_code_section_max_stack_size_too_large", + sections=[ + Section.Code( + code=Op.CALLER * 1024 + Op.POP * 1024 + Op.STOP, + max_stack_height=1024, + ), + ], + # TODO auto types section generation probably failed, the exception must be about code + validity_error=EOFException.MAX_STACK_HEIGHT_ABOVE_LIMIT, + ), + ], + ids=lambda c: c.name, +) +def test_invalid_containers( + eof_test: EOFTestFiller, + container: Container, +): + """ + Test creating various types of valid EOF V1 contracts using legacy + initcode and a contract creating transaction. + """ + assert container.validity_error is not None, "Invalid container without validity error" + eof_test( + data=bytes(container), + expect_exception=container.validity_error, + ) + + @pytest.mark.parametrize("magic_0", [0, 1, 0xEE, 0xEF, 0xF0, 0xFF]) @pytest.mark.parametrize("magic_1", [0, 1, 2, 0xFE, 0xFF]) def test_magic_validation( @@ -81,7 +1164,7 @@ def test_single_code_section( sections.append(Section.Data(data=b"\0")) eof_test( data=Container( - name="max_code_sections", + name="single_code_section", sections=sections, kind=ContainerKind.INITCODE if plus_container else ContainerKind.RUNTIME, ), diff --git a/tests/prague/eip7692_eof_v1/tracker.md b/tests/prague/eip7692_eof_v1/tracker.md index 26d5d22b7c..baba0b5923 100644 --- a/tests/prague/eip7692_eof_v1/tracker.md +++ b/tests/prague/eip7692_eof_v1/tracker.md @@ -1,85 +1,83 @@ # EOF Testing Coverage Tracker - [ ] Example Test Case 1 -- [x] Example Test Case 2 (./eip3540_eof_v1/test_example_valid_invalid.py::test_example_valid_invalid) -- [ ] Example Test Case 3 (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml) +- [x] Example Test Case 2 (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_example_valid_invalid.py::test_example_valid_invalid`) ## EIP-3540: EOF - EVM Object Format v1 ### Validation -- [ ] Empty code is not a valid EOF (ethereum/tests: src/EOFTestsFiller/efValidation/validate_empty_code_Copier.json) -- [ ] Valid container without data section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/minimal_valid_EOF1_code_Copier.json) -- [ ] Valid container with data section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/minimal_valid_EOF1_code_with_data_Copier.json) -- [ ] Valid container with truncated data section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_truncated_section_Copier.json) -- [ ] Valid container with data section truncated to empty (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Valid containers with multiple code sections (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml src/EOFTestsFiller/efValidation/minimal_valid_EOF1_multiple_code_sections_Copier.json) -- [ ] Valid containers with max number of code sections (ethereum/tests: src/EOFTestsFiller/efValidation/many_code_sections_1024_Copier.json src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) -- [ ] Too many code sections (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_too_many_code_sections_Copier.json src/EOFTestsFiller/efValidation/too_many_code_sections_Copier.json) -- [ ] Truncated magic (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [x] Valid container except magic (./eip3540_eof_v1/test_container_validation.py::test_magic_validation ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/validate_EOF_prefix_Copier.json) -- [ ] Truncated before version (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [x] Valid container except version (./eip3540_eof_v1/test_container_validation.py::test_version_validation ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/validate_EOF_version_Copier.json) -- [ ] Truncated before type section header (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Truncated before type section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [ ] Truncated type section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [ ] No type section header (ethereum/tests: src/EOFTestsFiller/efValidation/EOF1_no_type_section_Copier.json) -- [ ] Truncated before code section header (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml) -- [ ] Truncated before code section number (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml ) -- [ ] Truncated code section number (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [ ] Truncated before code section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Truncated code section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [ ] No code section header (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_code_section_missing_Copier.json) -- [ ] 0 code section number (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml) -- [ ] 0 code section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml ./src/EOFTestsFiller/efValidation/EOF1_code_section_0_size_Copier.json) -- [ ] 0 code section size with non-empty data section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] No container sections, truncated before data section header (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Container sections present, truncated before data section header (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml) -- [ ] Truncated before data section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [ ] Truncated data section size (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_incomplete_section_size_Copier.json) -- [x] Truncated before header terminator (ethereum/tests: src/EOFTestsFiller/efValidation/EOF1_header_not_terminated_Copier.json) -- [ ] Truncated before header terminator (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Truncated before type section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_truncated_section_Copier.json) -- [ ] Type section truncated before outputs (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Type section truncated before max_stack_height (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Type section truncated max_stack_height (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_truncated_section_Copier.json) -- [ ] Truncated before code sections (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Truncated code section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_truncated_section_Copier.json) -- [ ] Data section empty, trailing bytes (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_trailing_bytes_Copier.json) -- [ ] Data section non-empty, trailing bytes (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_trailing_bytes_Copier.json) -- [ ] Wrong order of sections (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_section_order_Copier.json ./src/EOFTestsFiller/efValidation/EOF1_data_section_before_code_section_Copier.json ./src/EOFTestsFiller/efValidation/EOF1_data_section_before_types_section_Copier.json src/EOFTestsFiller/efValidation/EOF1_type_section_not_first_Copier.json) -- [ ] No data section header (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml src/EOFTestsFiller/efValidation/data_section_missing_Copier.json) -- [ ] Multiple data sections (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Unknown section id (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_unknown_section_Copier.json) -- [ ] Type section size != 4 * code section number (ethereum/tests: ./src/EOFTestsFiller/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_invalid_type_section_size_Copier.json src/EOFTestsFiller/efValidation/EOF1_types_section_0_size_Copier.json) -- [ ] Code section with max max_stack_height (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml) -- [ ] Code section with max_stack_height above limit (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/efValidation/max_stack_height_Copier.json) -- [ ] Valid code sections with inputs/outputs (ethereum/tests: ./src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) -- [ ] Valid code section with max inputs -- [ ] Valid code section with max outputs -- [ ] Code sections with invalid number of inputs/outputs (above limit) -- [ ] 0 section with inputs/outputs (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_invalid_section_0_type_Copier.json src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) -- [ ] Multiple type section headers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_multiple_type_sections_Copier.json) -- [ ] Multiple code section headers (ethereum/tests: src/EOFTestsFiller/efValidation/multiple_code_sections_headers_Copier.json) -- [ ] Multiple data section headers (ethereum/tests: src/EOFTestsFiller/efValidation/EOF1_multiple_data_sections_Copier.json) -- [ ] Container without type section (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/efValidation/EOF1_type_section_missing_Copier.json src/EOFTestsFiller/efValidation/EOF1_types_section_missing_Copier.json) -- [ ] Container without code sections (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Container without data section (ethereum/tests: ./src/EOFTestsFiller/EIP3540/validInvalidFiller.yml) -- [ ] Valid containers without data section and with subcontainers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_Copier.json) -- [ ] Valid containers with data section and with subcontainers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_Copier.json) -- [ ] Valid container with maximum number of subcontainers (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_Copier.json) -- [ ] Container with number of subcontainers above the limit (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Subcontainer section header truncated before subcontainer number (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Subcontainer section header truncated before subcontainer size (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Truncated subcontainer size (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] 0 container section number (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] 0 container size (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Truncated container section body (ethereum/tests: ./src/EOFTestsFiller/efValidation/EOF1_embedded_container_invalid_Copier.json) -- [ ] Multiple container section headers -- [ ] Invalid subcontainer -- [ ] Invalid subcontainer on a deep nesting level -- [ ] Max number of inputs/outputs in a section (ethereum/tests: src/EOFTestsFiller/efValidation/max_arguments_count_Copier.json) -- [ ] Number of inputs/outputs in a section above the limit (ethereum/tests: src/EOFTestsFiller/efValidation/max_arguments_count_Copier.json) +- [x] Empty code is not a valid EOF (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_invalid_containers -k empty_container`) +- [x] Valid container without data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_invalid_containers -k single_code_section_no_data_section`) +- [x] Valid container with data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_valid_containers -k single_code_section_with_data_section`) +- [x] Valid container with truncated data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_invalid_containers -k data_section_contents_incomplete`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1test_migrated_valid_invalid.py::test_migrated_valid_invalid -k data_section_contents_incomplete`) +- [x] Valid container with data section truncated to empty (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_invalid_containers -k no_data_section_contents`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1test_migrated_valid_invalid.py::test_migrated_valid_invalid -k no_data_section_contents`) +- [x] Valid containers with multiple code sections (`tests/prague/eip7692_eof_v1/tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_valid_containers -k multiple_code_sections`) +- [x] Valid containers with max number of code sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_max_code_sections`) +- [x] Too many code sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k too_many_code_sections`) +- [x] Truncated magic (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k incomplete_magic`) +- [x] Valid container except magic (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_magic_validation`) +- [x] Truncated before version (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_version`) +- [x] Valid container except version (`tests/prague/eip7692_eof_v1/eip3540_eof_v1test_container_validation.py::test_version_validation`) +- [x] Truncated before type section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_type_header`) +- [x] Truncated before type section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_type_section_size`) +- [x] Truncated type section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k incomplete_type_section_size`) +- [x] No type section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k test_position_CasePosition.HEADER-section_test_SectionTest.MISSING-section_kind_TYPE`) +- [x] Truncated before code section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_code_header`) +- [x] Truncated before code section number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k code_section_count_missing`) +- [x] Truncated code section number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k code_section_count_incomplete`) +- [x] Truncated before code section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k code_section_size_missing`) +- [x] Truncated code section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k code_section_size_incomplete`) +- [x] No code section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k test_position_CasePosition.HEADER-section_test_SectionTest.MISSING-section_kind_CODE`) +- [x] Zero code section number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k zero_code_sections_header`) +- [x] Zero code section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k empty_code_section`) +- [x] Zero code section size with non-empty data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k empty_code_section_with_non_empty_data`) +- [x] No container sections, truncated before data section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_header_data_section`) +- [x] Container sections present, truncated before data section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_header_data_section_with_container_section`) +- [x] Truncated before data section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_data_section_size`) +- [x] Truncated data section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k data_section_size_incomplete`) +- [x] Truncated before header terminator (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k terminator_incomplete`) +- [x] Truncated before type section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_before_type_section`) +- [x] Type section truncated before outputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_type_section_before_outputs`) +- [x] Type section truncated before max_stack_height (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_type_section_before_max_stack_height`) +- [x] Type section truncated max_stack_height (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k truncated_type_section_truncated_max_stack_height`) +- [x] Truncated before code sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_code_section_contents`) +- [x] Truncated code section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k incomplete_code_section_contents`) +- [x] Data section empty, trailing bytes (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k no_data_section_contents`) +- [x] Data section non-empty, trailing bytes (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k trailing_bytes_after_data_section`) +- [x] Wrong order of sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py`) +- [x] No data section header (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k test_position_CasePosition.HEADER-section_test_SectionTest.MISSING-section_kind_DATA`) +- [x] Multiple data sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k multiple_data_sections`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k multiple_code_and_data_sections`) +- [x] Unknown section id (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k unknown_section_1`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k unknown_section_2`) +- [x] Type section size != 4 * code section number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k type_section_too`) +- [x] Code section with max max_stack_height (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_valid_containers -k single_code_section_max_stack_size`) +- [x] Code section with max_stack_height above limit (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_invalid_containers -k single_code_section_max_stack_size_too_large`) +- [x] Valid code sections with inputs/outputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_with_inputs_outputs`) +- [x] Valid code section with max inputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_input_maximum`) +- [x] Valid code section with max outputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_output_maximum`) +- [x] Code sections with invalid number of inputs/outputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_input_too_large`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_output_too_large`) +- [x] First section with inputs/outputs (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k invalid_first_code_section`) +- [x] Multiple type section headers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k too_many_type_sections`) +- [x] Multiple code section headers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k multiple_code_headers`) +- [x] Multiple data section headers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k multiple_data_sections`) +- [x] Container without type section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k 'SectionTest.MISSING-section_kind_TYPE'`) +- [x] Container without code sections (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k 'SectionTest.MISSING-section_kind_CODE'`) +- [x] Container without data section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py::test_section_order -k 'SectionTest.MISSING-section_kind_DATA'`) +- [x] Valid containers without data section and with subcontainers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_valid_containers[fork_CancunEIP7692-eof_test-single_subcontainer_without_data]`) +- [x] Valid containers with data section and with subcontainers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_valid_containers[fork_CancunEIP7692-eof_test-single_subcontainer_with_data]`) +- [x] Valid container with maximum number of subcontainers (`tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py::test_wide_container[fork_CancunEIP7692-eof_test-256]`) +- [x] Container with number of subcontainers above the limit (`tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py::test_wide_container[fork_CancunEIP7692-eof_test-257]`) +- [x] Subcontainer section header truncated before subcontainer number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k no_container_section_count`) +- [x] Subcontainer section header truncated before subcontainer size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k incomplete_container_section_count`) +- [x] Truncated subcontainer size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k no_container_section_size`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k incomplete_container_section_size`) +- [x] Zero container section number (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k zero_container_section_count`) +- [x] Zero container section size (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k zero_size_container_section`) +- [x] Truncated container section body (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k no_container_section_contents`) +- [x] Multiple container section headers (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k multiple_container_headers`) +- [x] Invalid subcontainer (`tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py -k invalid`) +- [x] Invalid subcontainer on a deep nesting level (`tests/prague/eip7692_eof_v1/eip7620_eof_create/test_subcontainer_validation.py::test_deep_container`) +- [x] Max number of inputs/outputs in a section (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_valid_containers[fork_CancunEIP7692-eof_test-code_section_input_maximum]`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py::test_valid_containers[fork_CancunEIP7692-eof_test-code_section_output_maximum]`) +- [x] Number of inputs/outputs in a section above the limit (`tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_input_too_large`, `tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_validation.py -k code_section_output_too_large`) ### Execution @@ -331,8 +329,8 @@ ### Validation -- [ ] 0 section returning (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) -- [ ] 0 section declared non-returning but ends with RETF (ethereum/tests: src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) +- [ ] Zero section returning (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) +- [ ] Zero section declared non-returning but ends with RETF (ethereum/tests: src/EOFTestsFiller/EIP4750/validInvalidFiller.yml) - [ ] CALLF into non-returning function (ethereum/tests: src/EOFTestsFiller/efValidation/callf_into_nonreturning_Copier.json) - [ ] Valid JUMPF into sections with equal number of outputs (ethereum/tests: src/EOFTestsFiller/efValidation/jumpf_equal_outputs_Copier.json) - [ ] Valid JUMPF into sections with different but compatible number of outputs (ethereum/tests: src/EOFTestsFiller/efValidation/jumpf_compatible_outputs_Copier.json) From 09612b56c24df7e738391b24492351cb73481da3 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Mon, 2 Sep 2024 19:34:26 +0200 Subject: [PATCH 16/17] chore: use uv for package management (#777) Co-authored-by: Mario Vega --- .github/actions/build-fixtures/action.yaml | 37 +- .github/actions/setup-uv/action.yaml | 11 + .github/scripts/get_release_props.py | 29 + .github/workflows/coverage.yaml | 21 +- .github/workflows/docs_main.yaml | 44 +- .github/workflows/docs_tags.yaml | 46 +- .github/workflows/fixtures.yaml | 8 +- .github/workflows/fixtures_feature.yaml | 8 +- .github/workflows/tox_verify.yaml | 29 +- README.md | 8 +- docs/dev/docs.md | 23 +- docs/dev/precommit.md | 3 +- .../installation_troubleshooting.md | 2 +- docs/getting_started/quick_start.md | 7 +- docs/writing_tests/verifying_changes.md | 2 +- uv.lock | 2158 +++++++++++++++++ 16 files changed, 2311 insertions(+), 125 deletions(-) create mode 100644 .github/actions/setup-uv/action.yaml create mode 100644 .github/scripts/get_release_props.py create mode 100644 uv.lock diff --git a/.github/actions/build-fixtures/action.yaml b/.github/actions/build-fixtures/action.yaml index ea88950b67..f4a80dfc7d 100644 --- a/.github/actions/build-fixtures/action.yaml +++ b/.github/actions/build-fixtures/action.yaml @@ -1,37 +1,34 @@ -name: Build and Package Fixtures +name: Build and Package Fixture Release inputs: - name: - description: 'Name of the fixture package' + release_name: + description: 'Name of the fixture release' required: true runs: using: "composite" steps: - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: 3.11 - - name: Install yq + - name: Set up uv + uses: ./.github/actions/setup-uv + - name: Set up Python + shell: bash + run: uv python install 3.10 --no-progress + - name: Install EEST shell: bash - run: | - pip install yq - - name: Extract fixture properties + run: uv sync --no-progress + - name: Extract fixture release properties from config id: properties shell: bash run: | - yq -r --arg feature "${{ inputs.name }}" '.[$feature] | to_entries | map("\(.key)=\(.value)")[]' ./.github/configs/feature.yaml >> "$GITHUB_OUTPUT" + echo "release_name=${{ inputs.release_name }}" + uv run -q .github/scripts/get_release_props.py ${{ inputs.release_name }} >> "$GITHUB_OUTPUT" - uses: ./.github/actions/build-evm-base id: evm-builder with: type: ${{ steps.properties.outputs.evm-type }} - - name: Run fixtures fill + - name: Generate fixtures using fill shell: bash run: | - pip install --upgrade pip - python -m venv env - source env/bin/activate - pip install -e . - fill -n ${{ steps.evm-builder.outputs.x-dist }} --evm-bin=${{ steps.evm-builder.outputs.evm-bin }} --solc-version=${{ steps.properties.outputs.solc }} ${{ steps.properties.outputs.fill-params }} --output=fixtures_${{ inputs.name }}.tar.gz --build-name ${{ inputs.name }} + uv run fill -n ${{ steps.evm-builder.outputs.x-dist }} --evm-bin=${{ steps.evm-builder.outputs.evm-bin }} --solc-version=${{ steps.properties.outputs.solc }} ${{ steps.properties.outputs.fill-params }} --output=fixtures_${{ inputs.release_name }}.tar.gz --build-name ${{ inputs.release_name }} - uses: actions/upload-artifact@v4 with: - name: fixtures_${{ inputs.name }} - path: fixtures_${{ inputs.name }}.tar.gz \ No newline at end of file + name: fixtures_${{ inputs.release_name }} + path: fixtures_${{ inputs.release_name }}.tar.gz diff --git a/.github/actions/setup-uv/action.yaml b/.github/actions/setup-uv/action.yaml new file mode 100644 index 0000000000..6c78479b96 --- /dev/null +++ b/.github/actions/setup-uv/action.yaml @@ -0,0 +1,11 @@ +name: 'Setup UV' +description: 'Sets up uv with a fixed version' +runs: + using: 'composite' + steps: + - name: Install UV + shell: bash + run: | + UV_VERSION="0.4.2" + echo "Installing UV version $UV_VERSION..." + curl -LsSf https://astral.sh/uv/${UV_VERSION}/install.sh | sh diff --git a/.github/scripts/get_release_props.py b/.github/scripts/get_release_props.py new file mode 100644 index 0000000000..9ff05c7283 --- /dev/null +++ b/.github/scripts/get_release_props.py @@ -0,0 +1,29 @@ +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "pyyaml", +# "click", +# ] +# /// + +import sys + +import click +import yaml + +RELEASE_PROPS_FILE = './.github/configs/feature.yaml' + + +@click.command() +@click.argument('release', required=True) +def get_release_props(release): + """Extracts a specific property from the YAML file for a given release.""" + with open(RELEASE_PROPS_FILE) as f: + data = yaml.safe_load(f) + if release not in data: + print(f"Error: Release {release} not found in {RELEASE_PROPS_FILE}.") + sys.exit(1) + print("\n".join(f"{key}={value}" for key, value in data[release].items())) + +if __name__ == "__main__": + get_release_props() diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 885b696c44..65dbb8bdd3 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -31,12 +31,16 @@ jobs: echo $(pwd) echo ${{ github.workspace }} - #install pyspec deps from root repo - python3 --version - pip install --upgrade pip - python3 -m venv ./venv/ - source ./venv/bin/activate - pip install -e . + - name: Set up uv + uses: ./.github/actions/setup-uv + + - name: Set up Python + run: uv python install 3.10 + + - name: Install EEST + run: | + uv sync --no-progress + uv run python --version # Required to fill .py tests - name: Build GO EVM @@ -116,7 +120,6 @@ jobs: exit 1 fi done - # This command diffs the .py scripts introduced by a PR - name: Parse and fill introduced test sources @@ -151,8 +154,8 @@ jobs: mkdir -p fixtures/eof_tests echo "$files" | while read line; do file=$(echo "$line" | cut -c 3-) - fill $file --until=Cancun --evm-bin evmone-t8n --solc-version=0.8.25 || true >> filloutput.log 2>&1 - (fill $file --fork=CancunEIP7692 --evm-bin evmone-t8n --solc-version=0.8.25 -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 + uv run fill $file --until=Cancun --evm-bin evmone-t8n --solc-version=0.8.25 || true >> filloutput.log 2>&1 + (uv run fill $file --fork=CancunEIP7692 --evm-bin evmone-t8n --solc-version=0.8.25 -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1 done if grep -q "FAILURES" filloutput.log; then diff --git a/.github/workflows/docs_main.yaml b/.github/workflows/docs_main.yaml index 9cd97a5106..5794b28ec0 100644 --- a/.github/workflows/docs_main.yaml +++ b/.github/workflows/docs_main.yaml @@ -7,31 +7,25 @@ on: jobs: deploy: - if: github.repository_owner == 'ethereum' # don't run on forks + if: github.repository_owner == 'ethereum' # don't run on forks runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ssh-key: ${{secrets.GH_ACTIONS_DEPLOY_KEY}} - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -e .[docs] - - - name: Setup doc deploy - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email github-actions[bot]@users.noreply.github.com - - - name: Build and deploy docs to gh-pages - run: | - mike deploy --update-aliases --push --remote origin main development + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ssh-key: ${{secrets.GH_ACTIONS_DEPLOY_KEY}} + - name: Set up uv + uses: ./.github/actions/setup-uv + - name: Set up Python + run: uv python install 3.11 + - name: Install EEST and dependencies + run: uv sync --extra=docs --no-progress + - name: Setup doc deploy + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email github-actions[bot]@users.noreply.github.com + - name: Build and deploy docs to gh-pages + run: | + uv run mike deploy --update-aliases --push --remote origin main development diff --git a/.github/workflows/docs_tags.yaml b/.github/workflows/docs_tags.yaml index b40bb7136d..fc880953a9 100644 --- a/.github/workflows/docs_tags.yaml +++ b/.github/workflows/docs_tags.yaml @@ -3,35 +3,29 @@ name: Deploy Docs Tags on: push: tags: - - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10, v0.1.1a1 + - "v*" # Push events to matching v*, i.e. v1.0, v20.15.10, v0.1.1a1 jobs: deploy: - if: github.repository_owner == 'ethereum' # don't run on forks + if: github.repository_owner == 'ethereum' # don't run on forks runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ssh-key: ${{secrets.GH_ACTIONS_DEPLOY_KEY}} - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -e .[docs] - - - name: Setup doc deploy - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email github-actions[bot]@users.noreply.github.com - - - name: Build and deploy docs to gh-pages - run: | - mike deploy --update-aliases --push --remote origin ${{ github.ref_name }} latest + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ssh-key: ${{secrets.GH_ACTIONS_DEPLOY_KEY}} + - name: Set up uv + uses: ./.github/actions/setup-uv + - name: Set up Python + run: uv python install 3.11 + - name: Install EEST and dependencies + run: uv sync --extra=docs --no-progress + - name: Setup doc deploy + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email github-actions[bot]@users.noreply.github.com + - name: Build and deploy docs to gh-pages + run: | + uv run mike deploy --update-aliases --push --remote origin ${{ github.ref_name }} latest diff --git a/.github/workflows/fixtures.yaml b/.github/workflows/fixtures.yaml index d9f6a8c32f..759c5d624c 100644 --- a/.github/workflows/fixtures.yaml +++ b/.github/workflows/fixtures.yaml @@ -3,7 +3,7 @@ name: Build and Package Fixtures on: push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+*' + - "v[0-9]+.[0-9]+.[0-9]+*" workflow_dispatch: jobs: @@ -30,7 +30,7 @@ jobs: submodules: true - uses: ./.github/actions/build-fixtures with: - name: ${{ matrix.name }} + release_name: ${{ matrix.name }} release: runs-on: ubuntu-latest needs: build @@ -43,7 +43,7 @@ jobs: - name: Draft Release uses: softprops/action-gh-release@v2 with: - files: './**' + files: "./**" draft: true generate_release_notes: true - fail_on_unmatched_files: true \ No newline at end of file + fail_on_unmatched_files: true diff --git a/.github/workflows/fixtures_feature.yaml b/.github/workflows/fixtures_feature.yaml index befc7557a1..4798c68f64 100644 --- a/.github/workflows/fixtures_feature.yaml +++ b/.github/workflows/fixtures_feature.yaml @@ -3,7 +3,7 @@ name: Build and Package Fixtures for a feature on: push: tags: - - '*@v*' + - "*@v*" workflow_dispatch: jobs: @@ -34,7 +34,7 @@ jobs: submodules: true - uses: ./.github/actions/build-fixtures with: - name: ${{ matrix.feature }} + release_name: ${{ matrix.feature }} release: runs-on: ubuntu-latest needs: build @@ -47,8 +47,8 @@ jobs: - name: Draft Pre-release uses: softprops/action-gh-release@v2 with: - files: './**' + files: "./**" draft: true prerelease: true generate_release_notes: true - fail_on_unmatched_files: true \ No newline at end of file + fail_on_unmatched_files: true diff --git a/.github/workflows/tox_verify.yaml b/.github/workflows/tox_verify.yaml index f1f7fcbd6f..bebaf00f32 100644 --- a/.github/workflows/tox_verify.yaml +++ b/.github/workflows/tox_verify.yaml @@ -9,13 +9,13 @@ jobs: matrix: include: - os: ubuntu-latest - python: '3.10' - evm-type: 'stable' - tox-cmd: 'tox run-parallel --parallel-no-spinner' + python: "3.10" + evm-type: "stable" + tox-cmd: "tox" # run-parallel --parallel-no-spinner" # TODO: disable parallelisation for uv testing - os: ubuntu-latest - python: '3.12' - evm-type: 'stable' - tox-cmd: 'tox run-parallel --parallel-no-spinner' + python: "3.12" + evm-type: "stable" + tox-cmd: "tox" # run-parallel --parallel-no-spinner" # Disabled due to unavailable evm implementation for devnet-1 # - os: ubuntu-latest # python: '3.11' @@ -27,9 +27,9 @@ jobs: # evm-type: 'eip7692' # tox-cmd: 'tox -e tests-eip7692' - os: macos-latest - python: '3.11' - evm-type: 'stable' - tox-cmd: 'tox run-parallel --parallel-no-spinner' + python: "3.11" + evm-type: "stable" + tox-cmd: "tox" # run-parallel --parallel-no-spinner" steps: - uses: actions/checkout@v4 with: @@ -38,11 +38,10 @@ jobs: id: evm-builder with: type: ${{ matrix.evm-type }} - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python }} - allow-prereleases: true + - name: Set up uv + uses: ./.github/actions/setup-uv + - name: Set up Python ${{ matrix.python }} + run: uv python install ${{ matrix.python }} - name: Setup Tools/Dependencies Ubuntu if: runner.os == 'Linux' run: | @@ -54,7 +53,7 @@ jobs: # Add additional packages on 3.11: https://github.com/ethereum/execution-spec-tests/issues/274 if [ ${{ matrix.python }} == '3.11' ]; then brew install autoconf automake libtool; fi - name: Install Tox and any other packages - run: pip install tox + run: pip install tox-uv - name: Run Tox (CPython) run: ${{ matrix.tox-cmd }} - uses: DavidAnson/markdownlint-cli2-action@v16 diff --git a/README.md b/README.md index b5401fa99d..a96dd83947 100644 --- a/README.md +++ b/README.md @@ -98,14 +98,14 @@ This guide installs stable versions of the external (go-ethereum) `evm` executab Help for other platforms is available in the [online doc](https://ethereum.github.io/execution-spec-tests/getting_started/quick_start/). -2. Clone the [execution-spec-tests](https://github.com/ethereum/execution-spec-tests) repo and install its dependencies (it's recommended to use a virtual environment for the installation): +2. Clone the [execution-spec-tests](https://github.com/ethereum/execution-spec-tests) repo and install its dependencies ([`uv`](https://docs.astral.sh/uv/) will create and manage a virtual environment for its installation): ```console git clone https://github.com/ethereum/execution-spec-tests cd execution-spec-tests - python3 -m venv ./venv/ - source ./venv/bin/activate - pip install -e .[docs,lint,test] + pip install uv # or curl -LsSf https://astral.sh/uv/install.sh | sh + uv sync --all-extras + source .venv/bin/activate # or run `uv run fill ...` ``` 3. Verify the installation: diff --git a/docs/dev/docs.md b/docs/dev/docs.md index b6a5e1cad9..0e4cb33d06 100644 --- a/docs/dev/docs.md +++ b/docs/dev/docs.md @@ -5,7 +5,7 @@ The `execution-spec-tests` documentation is generated via [`mkdocs`](https://www ## Prerequisites ```console -pip install -e .[docs] +uv pip install -e .[docs] ``` ## Build the Documentation @@ -13,12 +13,13 @@ pip install -e .[docs] One time build: ```console -mkdocs build +uv run mkdocs build ``` -Pre-commit check: One time build and lint/type checking: +Do a pre-commit check: One time build and lint/type checking: ```console +pip install tox-uv tox -e docs ``` @@ -27,7 +28,7 @@ tox -e docs This runs continually: Deploys the site locally and re-generates the site upon modifications to `docs/**/*.md` or `tests/**/*.py`: ```console -mkdocs serve +uv run mkdocs serve ``` ## Remote Deployment and Versioning @@ -67,7 +68,7 @@ There are two workflows that automatically deploy updated/new versions of the do Build a new version and deploy it to remote (this version will then show up in the version selector list): ```console -mike deploy --push v1.2.3 +uv run mike deploy --push v1.2.3 ``` !!! note "Local deployment" @@ -78,7 +79,7 @@ mike deploy --push v1.2.3 Build, deploy and update the version an alias points to with: ```console -mike deploy --push --update-aliases v1.2.3 latest +uv run mike deploy --push --update-aliases v1.2.3 latest ``` where `v1.2.3` indicates the version's name and `development` is the alias. This will overwrite the version if it already exists. @@ -87,13 +88,13 @@ where `v1.2.3` indicates the version's name and `development` is the alias. This "main" is just a version name (intended to reflect that it is build from the main branch). However, `mike` will build the docs site from the current local repository state (including local modifications). Therefore, make sure you're on the HEAD of the main branch before executing (unless you know what you're doing :wink:)! ```console - mike deploy --push main + uv run mike deploy --push main ``` If the alias accidentally go change: ```console - mike deploy --push --update-aliases main development + uv run mike deploy --push --update-aliases main development ``` ### Viewing and Deleting Versions @@ -101,13 +102,13 @@ where `v1.2.3` indicates the version's name and `development` is the alias. This List versions: ```console -mike list +uv run mike list ``` Delete a version: ```console -mike delete v1.2.3a1-eof +uv run mike delete v1.2.3a1-eof ``` ### Set Default Version @@ -115,7 +116,7 @@ mike delete v1.2.3a1-eof Set the default version of the docs to open upon loading the page: ```console -mike set-default --push latest +uv run mike set-default --push latest ``` Typically, this must only be executed once for a repo. diff --git a/docs/dev/precommit.md b/docs/dev/precommit.md index a1e1f2bfd7..fdc9500c7d 100644 --- a/docs/dev/precommit.md +++ b/docs/dev/precommit.md @@ -5,8 +5,7 @@ There's a [pre-commit](https://pre-commit.com/) config file available in the rep To enable pre-commit, the following must be ran once: ```console -pip install pre-commit -pre-commit install +uvx pre-commit install ``` !!! note "Bypassing pre-commit checks" diff --git a/docs/getting_started/installation_troubleshooting.md b/docs/getting_started/installation_troubleshooting.md index f6c660d5dc..e8a9a30ee0 100644 --- a/docs/getting_started/installation_troubleshooting.md +++ b/docs/getting_started/installation_troubleshooting.md @@ -2,7 +2,7 @@ This page provides guidance on how to troubleshoot common issues that may arise when installing the Execution Spec Tests repository. -## Pip Installation Issues +## `uv`/`pip` Installation Issues ### Coincurve Installation diff --git a/docs/getting_started/quick_start.md b/docs/getting_started/quick_start.md index 17d401faf7..b6edc24139 100644 --- a/docs/getting_started/quick_start.md +++ b/docs/getting_started/quick_start.md @@ -48,9 +48,10 @@ The following requires a Python 3.10, 3.11 or 3.12 installation. ```console git clone https://github.com/ethereum/execution-spec-tests cd execution-spec-tests - python3 -m venv ./venv/ - source ./venv/bin/activate - pip install -e '.[docs,lint,test]' + pip install uv # or curl -LsSf https://astral.sh/uv/install.sh | sh + uv sync --all-extras + uv run solc-select use 0.8.24 --always-install + source .venv/bin/activate # or run `uv run fill ...` ``` 3. Verify installation: diff --git a/docs/writing_tests/verifying_changes.md b/docs/writing_tests/verifying_changes.md index 04dd7ae6a3..273fd1520f 100644 --- a/docs/writing_tests/verifying_changes.md +++ b/docs/writing_tests/verifying_changes.md @@ -12,7 +12,7 @@ The `tox` tool can be executed locally to check that local changes won't cause G ```console python -m venv ./venv/ source ./venv/bin/activate -pip install tox +pip install tox-uv ``` ### Execution diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000000..ed7148034c --- /dev/null +++ b/uv.lock @@ -0,0 +1,2158 @@ +version = 1 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version < '3.13'", + "python_full_version >= '3.13'", +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, +] + +[[package]] +name = "asn1crypto" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/cf/d547feed25b5244fcb9392e288ff9fdc3280b10260362fc45d37a798a6ee/asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", size = 121080 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/7f/09065fd9e27da0eda08b4d6897f1c13535066174cc023af248fc2a8d5e5a/asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67", size = 105045 }, +] + +[[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 = "beautifulsoup4" +version = "4.12.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/ca/824b1195773ce6166d388573fc106ce56d4a805bd7427b624e063596ec58/beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", size = 581181 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 }, +] + +[[package]] +name = "bidict" +version = "0.23.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/026678aa5a830e07cd9498a05d3e7e650a4f56a42f267a53d22bcda1bdc9/bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71", size = 29093 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764 }, +] + +[[package]] +name = "black" +version = "22.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ee/1f/b29c7371958ab41a800f8718f5d285bf4333b8d0b5a5a8650234463ee644/black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79", size = 554277 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/1b/3ba8128f0b6e86d87343a1275e17baeeeee1a89e02d2a0d275f472be3310/black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09", size = 2392131 }, + { url = "https://files.pythonhosted.org/packages/31/1a/0233cdbfbcfbc0864d815cf28ca40cdb65acf3601f3bf943d6d04e867858/black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb", size = 1339315 }, + { url = "https://files.pythonhosted.org/packages/4f/98/8f775455f99a8e4b16d8d26efdc8292f99b1c0ebfe04357d800ff379c0ae/black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a", size = 1212888 }, + { url = "https://files.pythonhosted.org/packages/93/98/6f7c2f7f81d87b5771febcee933ba58640fca29a767262763bc353074f63/black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968", size = 1474258 }, + { url = "https://files.pythonhosted.org/packages/5f/10/613ddfc646a1f51f24ad9173e4969025210fe9034a69718f08297ecb9b76/black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d", size = 1137867 }, + { url = "https://files.pythonhosted.org/packages/2e/ef/a38a2189959246543e60859fb65bd3143129f6d18dfc7bcdd79217f81ca2/black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72", size = 153859 }, +] + +[[package]] +name = "bracex" +version = "2.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/f1/ac657fd234f4ee61da9d90f2bae7d6078074de2f97cb911743faa8d10a91/bracex-2.5.tar.gz", hash = "sha256:0725da5045e8d37ea9592ab3614d8b561e22c3c5fde3964699be672e072ab611", size = 26622 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/4f/54d324c35221c027ca77e9aae418f525003bd0cc2613eea162a1246b5a92/bracex-2.5-py3-none-any.whl", hash = "sha256:d2fcf4b606a82ac325471affe1706dd9bbaa3536c91ef86a31f6b766f3dad1d0", size = 11509 }, +] + +[[package]] +name = "cached-property" +version = "1.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/61/2c/d21c1c23c2895c091fa7a91a54b6872098fea913526932d21902088a7c41/cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130", size = 12244 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/19/f2090f7dad41e225c7f2326e4cfe6fff49e57dedb5b53636c9551f86b069/cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0", size = 7573 }, +] + +[[package]] +name = "cairocffi" +version = "1.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/c5/1a4dc131459e68a173cbdab5fad6b524f53f9c1ef7861b7698e998b837cc/cairocffi-1.7.1.tar.gz", hash = "sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b", size = 88096 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d8/ba13451aa6b745c49536e87b6bf8f629b950e84bd0e8308f7dc6883b67e2/cairocffi-1.7.1-py3-none-any.whl", hash = "sha256:9803a0e11f6c962f3b0ae2ec8ba6ae45e957a146a004697a1ac1bbf16b073b3f", size = 75611 }, +] + +[[package]] +name = "cairosvg" +version = "2.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cairocffi" }, + { name = "cssselect2" }, + { name = "defusedxml" }, + { name = "pillow" }, + { name = "tinycss2" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d5/e6/ec5900b724e3c44af7f6f51f719919137284e5da4aabe96508baec8a1b40/CairoSVG-2.7.1.tar.gz", hash = "sha256:432531d72347291b9a9ebfb6777026b607563fd8719c46ee742db0aef7271ba0", size = 8399085 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/a5/1866b42151f50453f1a0d28fc4c39f5be5f412a2e914f33449c42daafdf1/CairoSVG-2.7.1-py3-none-any.whl", hash = "sha256:8a5222d4e6c3f86f1f7046b63246877a63b49923a1cd202184c3a634ef546b3b", size = 43235 }, +] + +[[package]] +name = "certifi" +version = "2024.7.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/02/a95f2b11e207f68bc64d7aae9666fed2e2b3f307748d5123dffb72a1bbea/certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b", size = 164065 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/d5/c84e1a17bf61d4df64ca866a1c9a913874b4e9bdc131ec689a0ad013fb36/certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90", size = 162960 }, +] + +[[package]] +name = "cffi" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1e/bf/82c351342972702867359cfeba5693927efe0a8dd568165490144f554b18/cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76", size = 516073 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/2a/9071bf1e20bf9f695643b6c3e0f838f340b95ee29de0d1bb7968772409be/cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb", size = 181841 }, + { url = "https://files.pythonhosted.org/packages/4b/42/60116f10466d692b64aef32ac40fd79b11344ab6ef889ff8e3d047f2fcb2/cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a", size = 178242 }, + { url = "https://files.pythonhosted.org/packages/26/8e/a53f844454595c6e9215e56cda123db3427f8592f2c7b5ef1be782f620d6/cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42", size = 425676 }, + { url = "https://files.pythonhosted.org/packages/60/ac/6402563fb40b64c7ccbea87836d9c9498b374629af3449f3d8ff34df187d/cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d", size = 447842 }, + { url = "https://files.pythonhosted.org/packages/b2/e7/e2ffdb8de59f48f17b196813e9c717fbed2364e39b10bdb3836504e89486/cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2", size = 455224 }, + { url = "https://files.pythonhosted.org/packages/59/55/3e8968e92fe35c1c368959a070a1276c10cae29cdad0fd0daa36c69e237e/cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab", size = 436341 }, + { url = "https://files.pythonhosted.org/packages/7f/df/700aaf009dfbfa04acb1ed487586c03c788c6a312f0361ad5f298c5f5a7d/cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b", size = 445861 }, + { url = "https://files.pythonhosted.org/packages/5a/70/637f070aae533ea11ab77708a820f3935c0edb4fbcef9393b788e6f426a5/cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206", size = 460982 }, + { url = "https://files.pythonhosted.org/packages/f7/1a/7d4740fa1ccc4fcc888963fc3165d69ef1a2c8d42c8911c946703ff5d4a5/cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa", size = 438434 }, + { url = "https://files.pythonhosted.org/packages/d0/d9/c48cc38aaf6f53a8b5d2dbf6fe788410fcbab33b15a69c56c01d2b08f6a2/cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f", size = 461219 }, + { url = "https://files.pythonhosted.org/packages/26/ec/b6a7f660a7f27bd2bb53fe99a2ccafa279088395ec8639b25b8950985b2d/cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc", size = 171406 }, + { url = "https://files.pythonhosted.org/packages/08/42/8c00824787e6f5ec55194f5cd30c4ba4b9d9d5bb0d4d0007b1bb948d4ad4/cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2", size = 180809 }, + { url = "https://files.pythonhosted.org/packages/53/cc/9298fb6235522e00e47d78d6aa7f395332ef4e5f6fe124f9a03aa60600f7/cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720", size = 181912 }, + { url = "https://files.pythonhosted.org/packages/e7/79/dc5334fbe60635d0846c56597a8d2af078a543ff22bc48d36551a0de62c2/cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9", size = 178297 }, + { url = "https://files.pythonhosted.org/packages/39/d7/ef1b6b16b51ccbabaced90ff0d821c6c23567fc4b2e4a445aea25d3ceb92/cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb", size = 444909 }, + { url = "https://files.pythonhosted.org/packages/29/b8/6e3c61885537d985c78ef7dd779b68109ba256263d74a2f615c40f44548d/cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424", size = 468854 }, + { url = "https://files.pythonhosted.org/packages/0b/49/adad1228e19b931e523c2731e6984717d5f9e33a2f9971794ab42815b29b/cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d", size = 476890 }, + { url = "https://files.pythonhosted.org/packages/76/54/c00f075c3e7fd14d9011713bcdb5b4f105ad044c5ad948db7b1a0a7e4e78/cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8", size = 459374 }, + { url = "https://files.pythonhosted.org/packages/f3/b9/f163bb3fa4fbc636ee1f2a6a4598c096cdef279823ddfaa5734e556dd206/cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6", size = 466891 }, + { url = "https://files.pythonhosted.org/packages/31/52/72bbc95f6d06ff2e88a6fa13786be4043e542cb24748e1351aba864cb0a7/cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91", size = 477658 }, + { url = "https://files.pythonhosted.org/packages/67/20/d694811457eeae0c7663fa1a7ca201ce495533b646c1180d4ac25684c69c/cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8", size = 453890 }, + { url = "https://files.pythonhosted.org/packages/dc/79/40cbf5739eb4f694833db5a27ce7f63e30a9b25b4a836c4f25fb7272aacc/cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb", size = 478254 }, + { url = "https://files.pythonhosted.org/packages/e9/eb/2c384c385cca5cae67ca10ac4ef685277680b8c552b99aedecf4ea23ff7e/cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9", size = 171285 }, + { url = "https://files.pythonhosted.org/packages/ca/42/74cb1e0f1b79cb64672f3cb46245b506239c1297a20c0d9c3aeb3929cb0c/cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0", size = 180842 }, + { url = "https://files.pythonhosted.org/packages/1a/1f/7862231350cc959a3138889d2c8d33da7042b22e923457dfd4cd487d772a/cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc", size = 182826 }, + { url = "https://files.pythonhosted.org/packages/8b/8c/26119bf8b79e05a1c39812064e1ee7981e1f8a5372205ba5698ea4dd958d/cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59", size = 178494 }, + { url = "https://files.pythonhosted.org/packages/61/94/4882c47d3ad396d91f0eda6ef16d45be3d752a332663b7361933039ed66a/cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb", size = 454459 }, + { url = "https://files.pythonhosted.org/packages/0f/7c/a6beb119ad515058c5ee1829742d96b25b2b9204ff920746f6e13bf574eb/cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195", size = 478502 }, + { url = "https://files.pythonhosted.org/packages/61/8a/2575cd01a90e1eca96a30aec4b1ac101a6fae06c49d490ac2704fa9bc8ba/cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e", size = 485381 }, + { url = "https://files.pythonhosted.org/packages/cd/66/85899f5a9f152db49646e0c77427173e1b77a1046de0191ab3b0b9a5e6e3/cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828", size = 470907 }, + { url = "https://files.pythonhosted.org/packages/00/13/150924609bf377140abe6e934ce0a57f3fc48f1fd956ec1f578ce97a4624/cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150", size = 479074 }, + { url = "https://files.pythonhosted.org/packages/17/fd/7d73d7110155c036303b0a6462c56250e9bc2f4119d7591d27417329b4d1/cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a", size = 484225 }, + { url = "https://files.pythonhosted.org/packages/fc/83/8353e5c9b01bb46332dac3dfb18e6c597a04ceb085c19c814c2f78a8c0d0/cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885", size = 488388 }, + { url = "https://files.pythonhosted.org/packages/73/0c/f9d5ca9a095b1fc88ef77d1f8b85d11151c374144e4606da33874e17b65b/cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492", size = 172096 }, + { url = "https://files.pythonhosted.org/packages/72/21/8c5d285fe20a6e31d29325f1287bb0e55f7d93630a5a44cafdafb5922495/cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2", size = 181478 }, + { url = "https://files.pythonhosted.org/packages/17/8f/581f2f3c3464d5f7cf87c2f7a5ba9acc6976253e02d73804240964243ec2/cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118", size = 182638 }, + { url = "https://files.pythonhosted.org/packages/8d/1c/c9afa66684b7039f48018eb11b229b659dfb32b7a16b88251bac106dd1ff/cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7", size = 178453 }, + { url = "https://files.pythonhosted.org/packages/cc/b6/1a134d479d3a5a1ff2fabbee551d1d3f1dd70f453e081b5f70d604aae4c0/cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377", size = 454441 }, + { url = "https://files.pythonhosted.org/packages/b1/b4/e1569475d63aad8042b0935dbf62ae2a54d1e9142424e2b0e924d2d4a529/cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb", size = 478543 }, + { url = "https://files.pythonhosted.org/packages/d2/40/a9ad03fbd64309dec5bb70bc803a9a6772602de0ee164d7b9a6ca5a89249/cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555", size = 485463 }, + { url = "https://files.pythonhosted.org/packages/a6/1a/f10be60e006dd9242a24bcc2b1cd55c34c578380100f742d8c610f7a5d26/cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204", size = 470854 }, + { url = "https://files.pythonhosted.org/packages/cc/b3/c035ed21aa3d39432bd749fe331ee90e4bc83ea2dbed1f71c4bc26c41084/cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f", size = 479096 }, + { url = "https://files.pythonhosted.org/packages/00/cb/6f7edde01131de9382c89430b8e253b8c8754d66b63a62059663ceafeab2/cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0", size = 484013 }, + { url = "https://files.pythonhosted.org/packages/b9/83/8e4e8c211ea940210d293e951bf06b1bfb90f2eeee590e9778e99b4a8676/cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4", size = 488119 }, + { url = "https://files.pythonhosted.org/packages/5e/52/3f7cfbc4f444cb4f73ff17b28690d12436dde665f67d68f1e1687908ab6c/cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a", size = 172122 }, + { url = "https://files.pythonhosted.org/packages/94/19/cf5baa07ee0f0e55eab7382459fbddaba0fdb0ba45973dd92556ae0d02db/cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7", size = 181504 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", size = 104809 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/61/095a0aa1a84d1481998b534177c8566fdc50bb1233ea9a0478cd3cc075bd/charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", size = 194219 }, + { url = "https://files.pythonhosted.org/packages/cc/94/f7cf5e5134175de79ad2059edf2adce18e0685ebdb9227ff0139975d0e93/charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", size = 122521 }, + { url = "https://files.pythonhosted.org/packages/46/6a/d5c26c41c49b546860cc1acabdddf48b0b3fb2685f4f5617ac59261b44ae/charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", size = 120383 }, + { url = "https://files.pythonhosted.org/packages/b8/60/e2f67915a51be59d4539ed189eb0a2b0d292bf79270410746becb32bc2c3/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", size = 138223 }, + { url = "https://files.pythonhosted.org/packages/05/8c/eb854996d5fef5e4f33ad56927ad053d04dc820e4a3d39023f35cad72617/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", size = 148101 }, + { url = "https://files.pythonhosted.org/packages/f6/93/bb6cbeec3bf9da9b2eba458c15966658d1daa8b982c642f81c93ad9b40e1/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", size = 140699 }, + { url = "https://files.pythonhosted.org/packages/da/f1/3702ba2a7470666a62fd81c58a4c40be00670e5006a67f4d626e57f013ae/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", size = 142065 }, + { url = "https://files.pythonhosted.org/packages/3f/ba/3f5e7be00b215fa10e13d64b1f6237eb6ebea66676a41b2bcdd09fe74323/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", size = 144505 }, + { url = "https://files.pythonhosted.org/packages/33/c3/3b96a435c5109dd5b6adc8a59ba1d678b302a97938f032e3770cc84cd354/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", size = 139425 }, + { url = "https://files.pythonhosted.org/packages/43/05/3bf613e719efe68fb3a77f9c536a389f35b95d75424b96b426a47a45ef1d/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", size = 145287 }, + { url = "https://files.pythonhosted.org/packages/58/78/a0bc646900994df12e07b4ae5c713f2b3e5998f58b9d3720cce2aa45652f/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", size = 149929 }, + { url = "https://files.pythonhosted.org/packages/eb/5c/97d97248af4920bc68687d9c3b3c0f47c910e21a8ff80af4565a576bd2f0/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", size = 141605 }, + { url = "https://files.pythonhosted.org/packages/a8/31/47d018ef89f95b8aded95c589a77c072c55e94b50a41aa99c0a2008a45a4/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", size = 142646 }, + { url = "https://files.pythonhosted.org/packages/ae/d5/4fecf1d58bedb1340a50f165ba1c7ddc0400252d6832ff619c4568b36cc0/charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", size = 92846 }, + { url = "https://files.pythonhosted.org/packages/a2/a0/4af29e22cb5942488cf45630cbdd7cefd908768e69bdd90280842e4e8529/charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", size = 100343 }, + { url = "https://files.pythonhosted.org/packages/68/77/02839016f6fbbf808e8b38601df6e0e66c17bbab76dff4613f7511413597/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", size = 191647 }, + { url = "https://files.pythonhosted.org/packages/3e/33/21a875a61057165e92227466e54ee076b73af1e21fe1b31f1e292251aa1e/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", size = 121434 }, + { url = "https://files.pythonhosted.org/packages/dd/51/68b61b90b24ca35495956b718f35a9756ef7d3dd4b3c1508056fa98d1a1b/charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", size = 118979 }, + { url = "https://files.pythonhosted.org/packages/e4/a6/7ee57823d46331ddc37dd00749c95b0edec2c79b15fc0d6e6efb532e89ac/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", size = 136582 }, + { url = "https://files.pythonhosted.org/packages/74/f1/0d9fe69ac441467b737ba7f48c68241487df2f4522dd7246d9426e7c690e/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", size = 146645 }, + { url = "https://files.pythonhosted.org/packages/05/31/e1f51c76db7be1d4aef220d29fbfa5dbb4a99165d9833dcbf166753b6dc0/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", size = 139398 }, + { url = "https://files.pythonhosted.org/packages/40/26/f35951c45070edc957ba40a5b1db3cf60a9dbb1b350c2d5bef03e01e61de/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", size = 140273 }, + { url = "https://files.pythonhosted.org/packages/07/07/7e554f2bbce3295e191f7e653ff15d55309a9ca40d0362fcdab36f01063c/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", size = 142577 }, + { url = "https://files.pythonhosted.org/packages/d8/b5/eb705c313100defa57da79277d9207dc8d8e45931035862fa64b625bfead/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", size = 137747 }, + { url = "https://files.pythonhosted.org/packages/19/28/573147271fd041d351b438a5665be8223f1dd92f273713cb882ddafe214c/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", size = 143375 }, + { url = "https://files.pythonhosted.org/packages/cf/7c/f3b682fa053cc21373c9a839e6beba7705857075686a05c72e0f8c4980ca/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", size = 148474 }, + { url = "https://files.pythonhosted.org/packages/1e/49/7ab74d4ac537ece3bc3334ee08645e231f39f7d6df6347b29a74b0537103/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", size = 140232 }, + { url = "https://files.pythonhosted.org/packages/2d/dc/9dacba68c9ac0ae781d40e1a0c0058e26302ea0660e574ddf6797a0347f7/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", size = 140859 }, + { url = "https://files.pythonhosted.org/packages/6c/c2/4a583f800c0708dd22096298e49f887b49d9746d0e78bfc1d7e29816614c/charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", size = 92509 }, + { url = "https://files.pythonhosted.org/packages/57/ec/80c8d48ac8b1741d5b963797b7c0c869335619e13d4744ca2f67fc11c6fc/charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", size = 99870 }, + { url = "https://files.pythonhosted.org/packages/d1/b2/fcedc8255ec42afee97f9e6f0145c734bbe104aac28300214593eb326f1d/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", size = 192892 }, + { url = "https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", size = 122213 }, + { url = "https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", size = 119404 }, + { url = "https://files.pythonhosted.org/packages/99/b0/9c365f6d79a9f0f3c379ddb40a256a67aa69c59609608fe7feb6235896e1/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", size = 137275 }, + { url = "https://files.pythonhosted.org/packages/91/33/749df346e93d7a30cdcb90cbfdd41a06026317bfbfb62cd68307c1a3c543/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", size = 147518 }, + { url = "https://files.pythonhosted.org/packages/72/1a/641d5c9f59e6af4c7b53da463d07600a695b9824e20849cb6eea8a627761/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", size = 140182 }, + { url = "https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", size = 141869 }, + { url = "https://files.pythonhosted.org/packages/df/3e/a06b18788ca2eb6695c9b22325b6fde7dde0f1d1838b1792a0076f58fe9d/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", size = 144042 }, + { url = "https://files.pythonhosted.org/packages/45/59/3d27019d3b447a88fe7e7d004a1e04be220227760264cc41b405e863891b/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", size = 138275 }, + { url = "https://files.pythonhosted.org/packages/7b/ef/5eb105530b4da8ae37d506ccfa25057961b7b63d581def6f99165ea89c7e/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", size = 144819 }, + { url = "https://files.pythonhosted.org/packages/a2/51/e5023f937d7f307c948ed3e5c29c4b7a3e42ed2ee0b8cdf8f3a706089bf0/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", size = 149415 }, + { url = "https://files.pythonhosted.org/packages/24/9d/2e3ef673dfd5be0154b20363c5cdcc5606f35666544381bee15af3778239/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", size = 141212 }, + { url = "https://files.pythonhosted.org/packages/5b/ae/ce2c12fcac59cb3860b2e2d76dc405253a4475436b1861d95fe75bdea520/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", size = 142167 }, + { url = "https://files.pythonhosted.org/packages/ed/3a/a448bf035dce5da359daf9ae8a16b8a39623cc395a2ffb1620aa1bce62b0/charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", size = 93041 }, + { url = "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", size = 100397 }, + { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, +] + +[[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 = "coincurve" +version = "20.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asn1crypto" }, + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/4c/9e5e51e6c12cec6444c86697992f9c6ccffa19f84d042ff939c8b89206ff/coincurve-20.0.0.tar.gz", hash = "sha256:872419e404300302e938849b6b92a196fabdad651060b559dc310e52f8392829", size = 122865 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/0c/f6a8b06f461089aeab441824134ea5d5824dba3acaac0a9dbf8444cbe1d6/coincurve-20.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d559b22828638390118cae9372a1bb6f6594f5584c311deb1de6a83163a0919b", size = 1255634 }, + { url = "https://files.pythonhosted.org/packages/62/c2/0dbabd2c6648f49f730fdcbba84c53b5ffaf452fca85c750633141fe049c/coincurve-20.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33d7f6ebd90fcc550f819f7f2cce2af525c342aac07f0ccda46ad8956ad9d99b", size = 1255532 }, + { url = "https://files.pythonhosted.org/packages/f5/77/c4fa50f8cb5d050a9bcab806503acdd1705b0dfb5c554eed15cc18bc12e8/coincurve-20.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22d70dd55d13fd427418eb41c20fde0a20a5e5f016e2b1bb94710701e759e7e0", size = 1191928 }, + { url = "https://files.pythonhosted.org/packages/a3/11/6254ea354a32a3a1d70722daf58f2ebf0f689f0940eaced5127233416553/coincurve-20.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f18d481eaae72c169f334cde1fd22011a884e0c9c6adc3fdc1fd13df8236a3", size = 1194364 }, + { url = "https://files.pythonhosted.org/packages/a7/a9/d8717d41eb02688691adc30d7348f7c5fdc78e977f4cea83ee84622050b5/coincurve-20.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9de1ec57f43c3526bc462be58fb97910dc1fdd5acab6c71eda9f9719a5bd7489", size = 1204658 }, + { url = "https://files.pythonhosted.org/packages/55/13/40923832d99c18fb01a00f83e5f6f702156e71cc0eb5d6281535eee662af/coincurve-20.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a6f007c44c726b5c0b3724093c0d4fb8e294f6b6869beb02d7473b21777473a3", size = 1215298 }, + { url = "https://files.pythonhosted.org/packages/4d/87/646462a7a7810c7a3dcadae8969e1b78d535bcff072c26b17588e93a39b8/coincurve-20.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0ff1f3b81330db5092c24da2102e4fcba5094f14945b3eb40746456ceabdd6d9", size = 1204504 }, + { url = "https://files.pythonhosted.org/packages/01/58/fbb9a312d559aee701491435b691e409fb0efa12eabf269ff651d537fed4/coincurve-20.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82f7de97694d9343f26bd1c8e081b168e5f525894c12445548ce458af227f536", size = 1209298 }, + { url = "https://files.pythonhosted.org/packages/ee/d0/1d5679c000b31f3b32512632d98571f2bb752cd25c127d6f5bf3711b6eae/coincurve-20.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:e905b4b084b4f3b61e5a5d58ac2632fd1d07b7b13b4c6d778335a6ca1dafd7a3", size = 1198934 }, + { url = "https://files.pythonhosted.org/packages/a3/f6/8c1499f730fac49ec13740fb1c015ce8082fa6b917790056988559f22212/coincurve-20.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:3657bb5ed0baf1cf8cf356e7d44aa90a7902cc3dd4a435c6d4d0bed0553ad4f7", size = 1193319 }, + { url = "https://files.pythonhosted.org/packages/24/a7/d60a41b3f0a546854c9b7ca65ab99a5fdf1c9e158ae264a580de8f23fd1c/coincurve-20.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:44087d1126d43925bf9a2391ce5601bf30ce0dba4466c239172dc43226696018", size = 1255635 }, + { url = "https://files.pythonhosted.org/packages/b7/4a/727fab66c0fbecfd7beeb38467910bd3652a77df649565e30160a9d2bae2/coincurve-20.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ccf0ba38b0f307a9b3ce28933f6c71dc12ef3a0985712ca09f48591afd597c8", size = 1255536 }, + { url = "https://files.pythonhosted.org/packages/0f/8b/25d4ae5bb60665023e6d71681fada88ee95b5010dae6fc0b44d8b23b8df1/coincurve-20.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:566bc5986debdf8572b6be824fd4de03d533c49f3de778e29f69017ae3fe82d8", size = 1191928 }, + { url = "https://files.pythonhosted.org/packages/0d/86/8c32c512fa27bfe7cfe70329fd43ebac23c0c8cec202cf6e4f52854e7ce3/coincurve-20.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4d70283168e146f025005c15406086513d5d35e89a60cf4326025930d45013a", size = 1194365 }, + { url = "https://files.pythonhosted.org/packages/fe/74/fefbe512f54df7d02a7ea4821b87cf199a91b3565cdf0c94448b3f6b1af1/coincurve-20.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:763c6122dd7d5e7a81c86414ce360dbe9a2d4afa1ca6c853ee03d63820b3d0c5", size = 1204658 }, + { url = "https://files.pythonhosted.org/packages/09/68/05b29f881f628ce8e8468f5f7420f6c4d7c129f43964e81d15bf388ae67a/coincurve-20.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f00c361c356bcea386d47a191bb8ac60429f4b51c188966a201bfecaf306ff7f", size = 1215301 }, + { url = "https://files.pythonhosted.org/packages/ee/5d/d91549cf5a163797b0724dc2dcd551b908b6beddb6598b37743df7f6f3ec/coincurve-20.0.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4af57bdadd2e64d117dd0b33cfefe76e90c7a6c496a7b034fc65fd01ec249b15", size = 1204505 }, + { url = "https://files.pythonhosted.org/packages/37/0f/898022e08760fb57d281f3695576e859b0f8a8ac629670223d9066c3f60d/coincurve-20.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a26437b7cbde13fb6e09261610b788ca2a0ca2195c62030afd1e1e0d1a62e035", size = 1209305 }, + { url = "https://files.pythonhosted.org/packages/57/b9/643567d3f680ddf8d1bf10a56112ae7755296500d8eaaef498be637a8533/coincurve-20.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:ed51f8bba35e6c7676ad65539c3dbc35acf014fc402101fa24f6b0a15a74ab9e", size = 1198932 }, + { url = "https://files.pythonhosted.org/packages/b3/3a/898f5c12469b292042608dd0702bcb0420ec32bac6b1ca2a0dd790f922bd/coincurve-20.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:594b840fc25d74118407edbbbc754b815f1bba9759dbf4f67f1c2b78396df2d3", size = 1193318 }, + { url = "https://files.pythonhosted.org/packages/8f/24/e1bf259dd57186fbdc7cec51909db320884162cfad5ec72cbaa63573ff9d/coincurve-20.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4df4416a6c0370d777aa725a25b14b04e45aa228da1251c258ff91444643f688", size = 1255671 }, + { url = "https://files.pythonhosted.org/packages/0a/c5/1817f87d1cd5ff50d8537fe60fb96f66b76dd02da885d970952e6189a801/coincurve-20.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1ccc3e4db55abf3fc0e604a187fdb05f0702bc5952e503d9a75f4ae6eeb4cb3a", size = 1255565 }, + { url = "https://files.pythonhosted.org/packages/90/9f/35e15f993717ed1dcc4c26d9771f073a1054af26808a0f421783bb4cd7e0/coincurve-20.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8335b1658a2ef5b3eb66d52647742fe8c6f413ad5b9d5310d7ea6d8060d40f", size = 1191953 }, + { url = "https://files.pythonhosted.org/packages/4a/3d/6a9bc32e69b738b5e05f5027bace1da6722352a4a447e495d3c03a601d99/coincurve-20.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ac025e485a0229fd5394e0bf6b4a75f8a4f6cee0dcf6f0b01a2ef05c5210ff", size = 1194425 }, + { url = "https://files.pythonhosted.org/packages/1a/a6/15424973dc47fc7c87e3c0f8859f6f1b1032582ee9f1b85fdd5d1e33d630/coincurve-20.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e46e3f1c21b3330857bcb1a3a5b942f645c8bce912a8a2b252216f34acfe4195", size = 1204678 }, + { url = "https://files.pythonhosted.org/packages/6a/e7/71ddb4d66c11c4ad13e729362f8852e048ae452eba3dfcf57751842bb292/coincurve-20.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:df9ff9b17a1d27271bf476cf3fa92df4c151663b11a55d8cea838b8f88d83624", size = 1215395 }, + { url = "https://files.pythonhosted.org/packages/b9/7d/03e0a19cfff1d86f5d019afc69cfbff02caada701ed5a4a50abc63d4261c/coincurve-20.0.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4155759f071375699282e03b3d95fb473ee05c022641c077533e0d906311e57a", size = 1204552 }, + { url = "https://files.pythonhosted.org/packages/07/cd/e9bd4ca7d931653a35c74194da04191a9aecc54b8f48a554cd538dc810e4/coincurve-20.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0530b9dd02fc6f6c2916716974b79bdab874227f560c422801ade290e3fc5013", size = 1209392 }, + { url = "https://files.pythonhosted.org/packages/99/54/260053f14f74b99b645084231e1c76994134ded49407a3bba23a8ffc0ff6/coincurve-20.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:eacf9c0ce8739c84549a89c083b1f3526c8780b84517ee75d6b43d276e55f8a0", size = 1198932 }, + { url = "https://files.pythonhosted.org/packages/b4/b5/c465e09345dd38b9415f5d47ae7683b3f461db02fcc03e699b6b5687ab2b/coincurve-20.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:52a67bfddbd6224dfa42085c88ad176559801b57d6a8bd30d92ee040de88b7b3", size = 1193324 }, +] + +[[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 = "colorlog" +version = "6.8.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/db/38/2992ff192eaa7dd5a793f8b6570d6bbe887c4fbbf7e72702eb0a693a01c8/colorlog-6.8.2.tar.gz", hash = "sha256:3e3e079a41feb5a1b64f978b5ea4f46040a94f11f0e8bbb8261e3dbbeca64d44", size = 16529 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/18/3e867ab37a24fdf073c1617b9c7830e06ec270b1ea4694a624038fc40a03/colorlog-6.8.2-py3-none-any.whl", hash = "sha256:4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33", size = 11357 }, +] + +[[package]] +name = "coverage" +version = "7.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/08/7e37f82e4d1aead42a7443ff06a1e406aabf7302c4f00a546e4b320b994c/coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", size = 798791 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/61/eb7ce5ed62bacf21beca4937a90fe32545c91a3c8a42a30c6616d48fc70d/coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", size = 206690 }, + { url = "https://files.pythonhosted.org/packages/7d/73/041928e434442bd3afde5584bdc3f932fb4562b1597629f537387cec6f3d/coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", size = 207127 }, + { url = "https://files.pythonhosted.org/packages/c7/c8/6ca52b5147828e45ad0242388477fdb90df2c6cbb9a441701a12b3c71bc8/coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", size = 235654 }, + { url = "https://files.pythonhosted.org/packages/d5/da/9ac2b62557f4340270942011d6efeab9833648380109e897d48ab7c1035d/coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc", size = 233598 }, + { url = "https://files.pythonhosted.org/packages/53/23/9e2c114d0178abc42b6d8d5281f651a8e6519abfa0ef460a00a91f80879d/coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", size = 234732 }, + { url = "https://files.pythonhosted.org/packages/0f/7e/a0230756fb133343a52716e8b855045f13342b70e48e8ad41d8a0d60ab98/coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", size = 233816 }, + { url = "https://files.pythonhosted.org/packages/28/7c/3753c8b40d232b1e5eeaed798c875537cf3cb183fb5041017c1fdb7ec14e/coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", size = 232325 }, + { url = "https://files.pythonhosted.org/packages/57/e3/818a2b2af5b7573b4b82cf3e9f137ab158c90ea750a8f053716a32f20f06/coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", size = 233418 }, + { url = "https://files.pythonhosted.org/packages/c8/fb/4532b0b0cefb3f06d201648715e03b0feb822907edab3935112b61b885e2/coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", size = 209343 }, + { url = "https://files.pythonhosted.org/packages/5a/25/af337cc7421eca1c187cc9c315f0a755d48e755d2853715bfe8c418a45fa/coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", size = 210136 }, + { url = "https://files.pythonhosted.org/packages/ad/5f/67af7d60d7e8ce61a4e2ddcd1bd5fb787180c8d0ae0fbd073f903b3dd95d/coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", size = 206796 }, + { url = "https://files.pythonhosted.org/packages/e1/0e/e52332389e057daa2e03be1fbfef25bb4d626b37d12ed42ae6281d0a274c/coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", size = 207244 }, + { url = "https://files.pythonhosted.org/packages/aa/cd/766b45fb6e090f20f8927d9c7cb34237d41c73a939358bc881883fd3a40d/coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", size = 239279 }, + { url = "https://files.pythonhosted.org/packages/70/6c/a9ccd6fe50ddaf13442a1e2dd519ca805cbe0f1fcd377fba6d8339b98ccb/coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", size = 236859 }, + { url = "https://files.pythonhosted.org/packages/14/6f/8351b465febb4dbc1ca9929505202db909c5a635c6fdf33e089bbc3d7d85/coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", size = 238549 }, + { url = "https://files.pythonhosted.org/packages/68/3c/289b81fa18ad72138e6d78c4c11a82b5378a312c0e467e2f6b495c260907/coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", size = 237477 }, + { url = "https://files.pythonhosted.org/packages/ed/1c/aa1efa6459d822bd72c4abc0b9418cf268de3f60eeccd65dc4988553bd8d/coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", size = 236134 }, + { url = "https://files.pythonhosted.org/packages/fb/c8/521c698f2d2796565fe9c789c2ee1ccdae610b3aa20b9b2ef980cc253640/coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", size = 236910 }, + { url = "https://files.pythonhosted.org/packages/7d/30/033e663399ff17dca90d793ee8a2ea2890e7fdf085da58d82468b4220bf7/coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", size = 209348 }, + { url = "https://files.pythonhosted.org/packages/20/05/0d1ccbb52727ccdadaa3ff37e4d2dc1cd4d47f0c3df9eb58d9ec8508ca88/coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", size = 210230 }, + { url = "https://files.pythonhosted.org/packages/7e/d4/300fc921dff243cd518c7db3a4c614b7e4b2431b0d1145c1e274fd99bd70/coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", size = 206983 }, + { url = "https://files.pythonhosted.org/packages/e1/ab/6bf00de5327ecb8db205f9ae596885417a31535eeda6e7b99463108782e1/coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", size = 207221 }, + { url = "https://files.pythonhosted.org/packages/92/8f/2ead05e735022d1a7f3a0a683ac7f737de14850395a826192f0288703472/coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", size = 240342 }, + { url = "https://files.pythonhosted.org/packages/0f/ef/94043e478201ffa85b8ae2d2c79b4081e5a1b73438aafafccf3e9bafb6b5/coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", size = 237371 }, + { url = "https://files.pythonhosted.org/packages/1f/0f/c890339dd605f3ebc269543247bdd43b703cce6825b5ed42ff5f2d6122c7/coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", size = 239455 }, + { url = "https://files.pythonhosted.org/packages/d1/04/7fd7b39ec7372a04efb0f70c70e35857a99b6a9188b5205efb4c77d6a57a/coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", size = 238924 }, + { url = "https://files.pythonhosted.org/packages/ed/bf/73ce346a9d32a09cf369f14d2a06651329c984e106f5992c89579d25b27e/coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", size = 237252 }, + { url = "https://files.pythonhosted.org/packages/86/74/1dc7a20969725e917b1e07fe71a955eb34bc606b938316bcc799f228374b/coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", size = 238897 }, + { url = "https://files.pythonhosted.org/packages/b6/e9/d9cc3deceb361c491b81005c668578b0dfa51eed02cd081620e9a62f24ec/coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", size = 209606 }, + { url = "https://files.pythonhosted.org/packages/47/c8/5a2e41922ea6740f77d555c4d47544acd7dc3f251fe14199c09c0f5958d3/coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", size = 210373 }, + { url = "https://files.pythonhosted.org/packages/8c/f9/9aa4dfb751cb01c949c990d136a0f92027fbcc5781c6e921df1cb1563f20/coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", size = 207007 }, + { url = "https://files.pythonhosted.org/packages/b9/67/e1413d5a8591622a46dd04ff80873b04c849268831ed5c304c16433e7e30/coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", size = 207269 }, + { url = "https://files.pythonhosted.org/packages/14/5b/9dec847b305e44a5634d0fb8498d135ab1d88330482b74065fcec0622224/coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", size = 239886 }, + { url = "https://files.pythonhosted.org/packages/7b/b7/35760a67c168e29f454928f51f970342d23cf75a2bb0323e0f07334c85f3/coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", size = 237037 }, + { url = "https://files.pythonhosted.org/packages/f7/95/d2fd31f1d638df806cae59d7daea5abf2b15b5234016a5ebb502c2f3f7ee/coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", size = 239038 }, + { url = "https://files.pythonhosted.org/packages/6e/bd/110689ff5752b67924efd5e2aedf5190cbbe245fc81b8dec1abaffba619d/coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", size = 238690 }, + { url = "https://files.pythonhosted.org/packages/d3/a8/08d7b38e6ff8df52331c83130d0ab92d9c9a8b5462f9e99c9f051a4ae206/coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", size = 236765 }, + { url = "https://files.pythonhosted.org/packages/d6/6a/9cf96839d3147d55ae713eb2d877f4d777e7dc5ba2bce227167d0118dfe8/coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", size = 238611 }, + { url = "https://files.pythonhosted.org/packages/74/e4/7ff20d6a0b59eeaab40b3140a71e38cf52547ba21dbcf1d79c5a32bba61b/coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", size = 209671 }, + { url = "https://files.pythonhosted.org/packages/35/59/1812f08a85b57c9fdb6d0b383d779e47b6f643bc278ed682859512517e83/coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", size = 210368 }, + { url = "https://files.pythonhosted.org/packages/9c/15/08913be1c59d7562a3e39fce20661a98c0a3f59d5754312899acc6cb8a2d/coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", size = 207758 }, + { url = "https://files.pythonhosted.org/packages/c4/ae/b5d58dff26cade02ada6ca612a76447acd69dccdbb3a478e9e088eb3d4b9/coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", size = 208035 }, + { url = "https://files.pythonhosted.org/packages/b8/d7/62095e355ec0613b08dfb19206ce3033a0eedb6f4a67af5ed267a8800642/coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", size = 250839 }, + { url = "https://files.pythonhosted.org/packages/7c/1e/c2967cb7991b112ba3766df0d9c21de46b476d103e32bb401b1b2adf3380/coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", size = 246569 }, + { url = "https://files.pythonhosted.org/packages/8b/61/a7a6a55dd266007ed3b1df7a3386a0d760d014542d72f7c2c6938483b7bd/coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", size = 248927 }, + { url = "https://files.pythonhosted.org/packages/c8/fa/13a6f56d72b429f56ef612eb3bc5ce1b75b7ee12864b3bd12526ab794847/coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", size = 248401 }, + { url = "https://files.pythonhosted.org/packages/75/06/0429c652aa0fb761fc60e8c6b291338c9173c6aa0f4e40e1902345b42830/coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", size = 246301 }, + { url = "https://files.pythonhosted.org/packages/52/76/1766bb8b803a88f93c3a2d07e30ffa359467810e5cbc68e375ebe6906efb/coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", size = 247598 }, + { url = "https://files.pythonhosted.org/packages/66/8b/f54f8db2ae17188be9566e8166ac6df105c1c611e25da755738025708d54/coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", size = 210307 }, + { url = "https://files.pythonhosted.org/packages/9f/b0/e0dca6da9170aefc07515cce067b97178cefafb512d00a87a1c717d2efd5/coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", size = 211453 }, + { url = "https://files.pythonhosted.org/packages/a5/2b/0354ed096bca64dc8e32a7cbcae28b34cb5ad0b1fe2125d6d99583313ac0/coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", size = 198926 }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "cssselect2" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tinycss2" }, + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e7/fc/326cb6f988905998f09bb54a3f5d98d4462ba119363c0dfad29750d48c09/cssselect2-0.7.0.tar.gz", hash = "sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a", size = 35888 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/3a/e39436efe51894243ff145a37c4f9a030839b97779ebcc4f13b3ba21c54e/cssselect2-0.7.0-py3-none-any.whl", hash = "sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969", size = 15586 }, +] + +[[package]] +name = "curdleproofs" +version = "0.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "merlin-transcripts" }, + { name = "py-arkworks-bls12381" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2b/a34bd43fa0432745f4acdd8d41a1d40450fabe66ff37f442a93db226bd9e/curdleproofs-0.1.1.tar.gz", hash = "sha256:85655359ccd67b3a93fa2152bcfc19dfd4cb4d0f4b1ef73181dfd34baf41fd42", size = 16636 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/42/da480809613592143fc8203b950b81f4d35d37adbcb2258d4d6279d910a9/curdleproofs-0.1.1-py3-none-any.whl", hash = "sha256:c9b847aa68fc086a8b17f004209ed630f349991c3f801e24ed51d77f54fcb11c", size = 24428 }, +] + +[[package]] +name = "cytoolz" +version = "0.12.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "toolz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/d8/8df71050b214686591241a1826d2e6934b5c295c5bc57f643e4ed697f1eb/cytoolz-0.12.3.tar.gz", hash = "sha256:4503dc59f4ced53a54643272c61dc305d1dbbfbd7d6bdf296948de9f34c3a282", size = 625899 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/11/ebc8b85c77cc2247c169af808901a80e5d29429b3c9b0d114d4048ad2a5a/cytoolz-0.12.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bbe58e26c84b163beba0fbeacf6b065feabc8f75c6d3fe305550d33f24a2d346", size = 413462 }, + { url = "https://files.pythonhosted.org/packages/19/22/57f20a9f135a08a6fc9848744c324c4facca2b1370a1ae4e8333e274c707/cytoolz-0.12.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c51b66ada9bfdb88cf711bf350fcc46f82b83a4683cf2413e633c31a64df6201", size = 396040 }, + { url = "https://files.pythonhosted.org/packages/12/30/337a18b1182888bf5d59357095a83f537a88e2db32ee0381166a83deddda/cytoolz-0.12.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e70d9c615e5c9dc10d279d1e32e846085fe1fd6f08d623ddd059a92861f4e3dd", size = 1933264 }, + { url = "https://files.pythonhosted.org/packages/93/a3/c244bfacd046316cd0a4cffd2e245a8dd9b685168497c3b7c776bdb72c59/cytoolz-0.12.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a83f4532707963ae1a5108e51fdfe1278cc8724e3301fee48b9e73e1316de64f", size = 2014114 }, + { url = "https://files.pythonhosted.org/packages/a6/40/51bdfe7fd1cad802eabebb7bb742e694227db25c4806eebf4358229e3220/cytoolz-0.12.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d028044524ee2e815f36210a793c414551b689d4f4eda28f8bbb0883ad78bf5f", size = 1999458 }, + { url = "https://files.pythonhosted.org/packages/f7/0b/5973e0ceab96349f9cabb3b20ecc3a717a19e355f68d354dfa538bebb226/cytoolz-0.12.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c2875bcd1397d0627a09a4f9172fa513185ad302c63758efc15b8eb33cc2a98", size = 1956106 }, + { url = "https://files.pythonhosted.org/packages/d3/01/bb850ad1467f0d1dc5a21a05e3df6ad308a19d095f07583c4e65a85e2ba8/cytoolz-0.12.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:131ff4820e5d64a25d7ad3c3556f2d8aa65c66b3f021b03f8a8e98e4180dd808", size = 1861974 }, + { url = "https://files.pythonhosted.org/packages/c9/97/207e544a2c9c3d8735102403982a319c252c337e9cf792c2753c22cff1b6/cytoolz-0.12.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:04afa90d9d9d18394c40d9bed48c51433d08b57c042e0e50c8c0f9799735dcbd", size = 1937926 }, + { url = "https://files.pythonhosted.org/packages/76/1e/6cc756537caef16cd491de1550c1f25140528785e28263326bd3243a19ed/cytoolz-0.12.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:dc1ca9c610425f9854323669a671fc163300b873731584e258975adf50931164", size = 1859141 }, + { url = "https://files.pythonhosted.org/packages/20/43/30819bbc4348cabb44d800ab0d0efb29a9d21db8f75060fd1199d5300953/cytoolz-0.12.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bfa3f8e01bc423a933f2e1c510cbb0632c6787865b5242857cc955cae220d1bf", size = 2013731 }, + { url = "https://files.pythonhosted.org/packages/bd/ab/cacabf2d0dfea006575fea900131eb491370ee1664783f80cb131f577001/cytoolz-0.12.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:f702e295dddef5f8af4a456db93f114539b8dc2a7a9bc4de7c7e41d169aa6ec3", size = 2015075 }, + { url = "https://files.pythonhosted.org/packages/79/6f/98eeee4f735bff536654625e0c38e50c4b01c13fbd9c744d3284dbccc54d/cytoolz-0.12.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0fbad1fb9bb47e827d00e01992a099b0ba79facf5e5aa453be066033232ac4b5", size = 1953391 }, + { url = "https://files.pythonhosted.org/packages/6a/81/80bcbc750e3c8f72d07f1e61c25597fdb23fec3c3d52542f220bff87372c/cytoolz-0.12.3-cp310-cp310-win32.whl", hash = "sha256:8587c3c3dbe78af90c5025288766ac10dc2240c1e76eb0a93a4e244c265ccefd", size = 320881 }, + { url = "https://files.pythonhosted.org/packages/45/9e/cce296c6da9404ce210c79700b85d9ba582a6e908ee88ec707efec09bcd9/cytoolz-0.12.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e45803d9e75ef90a2f859ef8f7f77614730f4a8ce1b9244375734567299d239", size = 362216 }, + { url = "https://files.pythonhosted.org/packages/98/8a/618a70326d4a52998a6bbb11ca019979891a51b85cbbfce8f9762eec5d2c/cytoolz-0.12.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3ac4f2fb38bbc67ff1875b7d2f0f162a247f43bd28eb7c9d15e6175a982e558d", size = 416356 }, + { url = "https://files.pythonhosted.org/packages/bb/17/542f708b9116aa8d8c9c5551500bfa6ab1bddd3edc11457070599a97c197/cytoolz-0.12.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0cf1e1e96dd86829a0539baf514a9c8473a58fbb415f92401a68e8e52a34ecd5", size = 398412 }, + { url = "https://files.pythonhosted.org/packages/d6/9c/52a0460f2b59009da63794cfe11ad002d55fc88fced6ccc85f7ae10a3259/cytoolz-0.12.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08a438701c6141dd34eaf92e9e9a1f66e23a22f7840ef8a371eba274477de85d", size = 2090389 }, + { url = "https://files.pythonhosted.org/packages/c7/6d/284d4a1f88b1e63b8a1c80162244ca5d4e0b31647c4f56186f3385fd0d0e/cytoolz-0.12.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6b6f11b0d7ed91be53166aeef2a23a799e636625675bb30818f47f41ad31821", size = 2187333 }, + { url = "https://files.pythonhosted.org/packages/3e/44/44efcf2acf824aefab5f3fdb97235d360c216c2425db391a8dee687f1774/cytoolz-0.12.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7fde09384d23048a7b4ac889063761e44b89a0b64015393e2d1d21d5c1f534a", size = 2173106 }, + { url = "https://files.pythonhosted.org/packages/6f/74/7c2d5af25d51f481e9be771bda2cf5496631cd0fba876d2cc0086caa732d/cytoolz-0.12.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d3bfe45173cc8e6c76206be3a916d8bfd2214fb2965563e288088012f1dabfc", size = 2098805 }, + { url = "https://files.pythonhosted.org/packages/e0/e5/9995bf66caee139459ab70d8b5820c37718d5f7e7380481adb85ef522e4d/cytoolz-0.12.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27513a5d5b6624372d63313574381d3217a66e7a2626b056c695179623a5cb1a", size = 1995956 }, + { url = "https://files.pythonhosted.org/packages/93/73/eee7a7f455d4691f1915b35d1713ba69c6851f940c6f8fffdd2efcbe4411/cytoolz-0.12.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d294e5e81ff094fe920fd545052ff30838ea49f9e91227a55ecd9f3ca19774a0", size = 2074891 }, + { url = "https://files.pythonhosted.org/packages/a3/c7/6f0c60bbb911ee3f33b243a695e2fc944285a1865bbb1dfefee1b7c35d62/cytoolz-0.12.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:727b01a2004ddb513496507a695e19b5c0cfebcdfcc68349d3efd92a1c297bf4", size = 1980228 }, + { url = "https://files.pythonhosted.org/packages/58/7c/d7524626b415d410208fd2774ff2824fab4dcbe4a496d53bdba85a1407df/cytoolz-0.12.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:fe1e1779a39dbe83f13886d2b4b02f8c4b10755e3c8d9a89b630395f49f4f406", size = 2147616 }, + { url = "https://files.pythonhosted.org/packages/a5/7b/9bdf8615e61958386f5c7108d857312214837ae3eacf3589873499d2f0aa/cytoolz-0.12.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:de74ef266e2679c3bf8b5fc20cee4fc0271ba13ae0d9097b1491c7a9bcadb389", size = 2148775 }, + { url = "https://files.pythonhosted.org/packages/45/91/b92ab0e29bf7cfaacfedc85391a0d0365a6ac74363f2532ba307a760db14/cytoolz-0.12.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e04d22049233394e0b08193aca9737200b4a2afa28659d957327aa780ddddf2", size = 2079810 }, + { url = "https://files.pythonhosted.org/packages/2f/33/8204d65871fa639d1d3ae788e3afc187f610126f53f2324d4aa37caf0630/cytoolz-0.12.3-cp311-cp311-win32.whl", hash = "sha256:20d36430d8ac809186736fda735ee7d595b6242bdb35f69b598ef809ebfa5605", size = 320212 }, + { url = "https://files.pythonhosted.org/packages/ab/e3/7ce2efaf243c9ee75fc730cd018981788b56e7ad3767f24e7a9cd14831ac/cytoolz-0.12.3-cp311-cp311-win_amd64.whl", hash = "sha256:780c06110f383344d537f48d9010d79fa4f75070d214fc47f389357dd4f010b6", size = 363570 }, + { url = "https://files.pythonhosted.org/packages/7f/57/b0feabefdff4707d0b96bf75e2298ecb209ba22c2e3fd15e5230dd68441a/cytoolz-0.12.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:86923d823bd19ce35805953b018d436f6b862edd6a7c8b747a13d52b39ed5716", size = 419825 }, + { url = "https://files.pythonhosted.org/packages/54/82/795aa9f91ee81818732b435755559857a76e16b7e435e1de434b47ce72b9/cytoolz-0.12.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3e61acfd029bfb81c2c596249b508dfd2b4f72e31b7b53b62e5fb0507dd7293", size = 401673 }, + { url = "https://files.pythonhosted.org/packages/23/f3/298f32b2e374f4f716ca74a9e46b64ee1df9f160de262391f7f9bc53ecca/cytoolz-0.12.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd728f4e6051af6af234651df49319da1d813f47894d4c3c8ab7455e01703a37", size = 2096352 }, + { url = "https://files.pythonhosted.org/packages/39/44/49929b33bd0cdccc98b281e4ca11f0836b2963c6fdec8ebb7891807ed908/cytoolz-0.12.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe8c6267caa7ec67bcc37e360f0d8a26bc3bdce510b15b97f2f2e0143bdd3673", size = 2161581 }, + { url = "https://files.pythonhosted.org/packages/e9/77/980a8bc123490dd7112e1e068da989932b7612504355ddd25593880c3156/cytoolz-0.12.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99462abd8323c52204a2a0ce62454ce8fa0f4e94b9af397945c12830de73f27e", size = 2178057 }, + { url = "https://files.pythonhosted.org/packages/23/d9/2f7a4db7f92eab4b567e56cc2fc147fed1ef35f7968e44cefcbbfb366980/cytoolz-0.12.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da125221b1fa25c690fcd030a54344cecec80074df018d906fc6a99f46c1e3a6", size = 2130881 }, + { url = "https://files.pythonhosted.org/packages/85/bf/1147229198a8fc3f2090d01263234d47b5b7f8c52c20090b1cceda0929cd/cytoolz-0.12.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c18e351956f70db9e2d04ff02f28e9a41839250d3f936a4c8a1eabd1c3094d2", size = 1979975 }, + { url = "https://files.pythonhosted.org/packages/5b/53/b730e9f428e74971f934bf73f0868099d325ffbf0c080a201bb16b6ab508/cytoolz-0.12.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:921e6d2440ac758c4945c587b1d1d9b781b72737ac0c0ca5d5e02ca1db8bded2", size = 2086861 }, + { url = "https://files.pythonhosted.org/packages/24/24/df510850c1c57ad69a23a2700083cfd285faf27d16e61f0e503eec122473/cytoolz-0.12.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1651a9bd591a8326329ce1d6336f3129161a36d7061a4d5ea9e5377e033364cf", size = 1973211 }, + { url = "https://files.pythonhosted.org/packages/b6/ad/a6e27924a6c8048b4f1ffbd8b9b0b871642bd94d3e457aa42a629c1f667b/cytoolz-0.12.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8893223b87c2782bd59f9c4bd5c7bf733edd8728b523c93efb91d7468b486528", size = 2133017 }, + { url = "https://files.pythonhosted.org/packages/26/a3/f9dfb406232d0a100994a86c123259cd2ab023aa8ae325b0d9926f80091f/cytoolz-0.12.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:e4d2961644153c5ae186db964aa9f6109da81b12df0f1d3494b4e5cf2c332ee2", size = 2156771 }, + { url = "https://files.pythonhosted.org/packages/fb/bf/ce2c6f6175a29c830904b23faee557de8c167255dbb2bb84e04d7cf5605a/cytoolz-0.12.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:71b6eb97f6695f7ba8ce69c49b707a351c5f46fd97f5aeb5f6f2fb0d6e72b887", size = 2121104 }, + { url = "https://files.pythonhosted.org/packages/bf/97/95a5fb2b5db9b1ea8856741a2a94741a71cb5640112403029beb7b3ef1df/cytoolz-0.12.3-cp312-cp312-win32.whl", hash = "sha256:cee3de65584e915053412cd178729ff510ad5f8f585c21c5890e91028283518f", size = 320537 }, + { url = "https://files.pythonhosted.org/packages/0a/11/3e69585342ce4e6b7f2f6139c8aa235dab5a4fe5c76a051fe01696618bd0/cytoolz-0.12.3-cp312-cp312-win_amd64.whl", hash = "sha256:9eef0d23035fa4dcfa21e570961e86c375153a7ee605cdd11a8b088c24f707f6", size = 363238 }, + { url = "https://files.pythonhosted.org/packages/00/8c/c58e2f14a88132722988ee0951b01ee6cc4880302384f064902d6e8fb048/cytoolz-0.12.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:55f9bd1ae6c2a27eda5abe2a0b65a83029d2385c5a1da7b8ef47af5905d7e905", size = 353101 }, + { url = "https://files.pythonhosted.org/packages/35/99/6ef817203004c7055370fa1ab3bb0dfc6b7ebd0b4942099ce86007614001/cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2d271393c378282727f1231d40391ae93b93ddc0997448acc21dd0cb6a1e56d", size = 385225 }, + { url = "https://files.pythonhosted.org/packages/a2/25/64e5907b15bd16f0f38e825762540ee3293b513f2eb4b9bb51b7f78d5457/cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee98968d6a66ee83a8ceabf31182189ab5d8598998c8ce69b6d5843daeb2db60", size = 405888 }, + { url = "https://files.pythonhosted.org/packages/17/c0/0e19ab05222cf2370d580e5500409c26266f89e853fa18b2b12c530f3957/cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01cfb8518828c1189200c02a5010ea404407fb18fd5589e29c126e84bbeadd36", size = 396781 }, + { url = "https://files.pythonhosted.org/packages/5e/39/bee67e2b541ca3478a982c68d7d23b718fa7f2947bdfc0eecdba9c4e0882/cytoolz-0.12.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:456395d7aec01db32bf9e6db191d667347c78d8d48e77234521fa1078f60dabb", size = 340712 }, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604 }, +] + +[[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-typing" +version = "3.5.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c8/52/f5d10803345dd06f9301b4871e8ebb39971a4238b60c61f84ffc83379611/eth-typing-3.5.2.tar.gz", hash = "sha256:22bf051ddfaa35ff827c30090de167e5c5b8cc6d343f7f35c9b1c7553f6ab64d", size = 16850 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/36/50c5d5f070b7e4318dc906f8bf642719418ffef741db94f85ab6447563e1/eth_typing-3.5.2-py3-none-any.whl", hash = "sha256:1842e628fb1ffa929b94f89a9d33caafbeb9978dc96abb6036a12bc91f1c624b", size = 14481 }, +] + +[[package]] +name = "eth-utils" +version = "2.3.1" +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/7c/17/8a43def3267f25df94fc0d3ef66a76b00aee7bab35b1d2ff41400eedec1a/eth-utils-2.3.1.tar.gz", hash = "sha256:56a969b0536d4969dcb27e580521de35abf2dbed8b1bf072b5c80770c4324e27", size = 74831 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/89/251f118fae703d5504bbe63b72124ef346a8a65c5ee0a106b5b7930c397f/eth_utils-2.3.1-py3-none-any.whl", hash = "sha256:614eedc5ffcaf4e6708ca39e23b12bd69526a312068c1170c773bd1307d13972", size = 77778 }, +] + +[[package]] +name = "eth2spec" +version = "1.5.0a3" +source = { git = "https://github.com/ethereum/consensus-specs.git?rev=d08a91cad5a8657e57750b7cfe3ac2178b3d9c0c#d08a91cad5a8657e57750b7cfe3ac2178b3d9c0c" } +dependencies = [ + { name = "curdleproofs" }, + { name = "eth-typing" }, + { name = "eth-utils" }, + { name = "lru-dict" }, + { name = "marko" }, + { name = "milagro-bls-binding" }, + { name = "py-arkworks-bls12381" }, + { name = "py-ecc" }, + { name = "pycryptodome" }, + { name = "remerkleable" }, + { name = "ruamel-yaml" }, + { name = "trie" }, +] + +[[package]] +name = "ethereum" +version = "0.1.0" +source = { git = "https://github.com/ethereum/execution-specs#fcd12750edd4443a91f138728689a1d0a503a7c1" } +dependencies = [ + { name = "coincurve" }, + { name = "eth2spec" }, + { name = "pycryptodome" }, + { name = "typing-extensions" }, +] + +[[package]] +name = "ethereum-execution-spec-tests" +version = "1.0.0" +source = { editable = "." } +dependencies = [ + { name = "bidict" }, + { name = "click" }, + { name = "coincurve" }, + { name = "colorlog" }, + { name = "ethereum" }, + { name = "filelock" }, + { name = "gitpython" }, + { name = "hive-py" }, + { name = "pydantic" }, + { name = "pyjwt" }, + { name = "pytest" }, + { name = "pytest-html" }, + { name = "pytest-metadata" }, + { name = "pytest-xdist" }, + { name = "requests" }, + { name = "rich" }, + { name = "semver" }, + { name = "setuptools" }, + { name = "solc-select" }, + { name = "tenacity" }, + { name = "trie" }, + { name = "types-setuptools" }, +] + +[package.optional-dependencies] +docs = [ + { name = "cairosvg" }, + { name = "mike" }, + { name = "mkdocs" }, + { name = "mkdocs-gen-files" }, + { name = "mkdocs-git-authors-plugin" }, + { name = "mkdocs-glightbox" }, + { name = "mkdocs-literate-nav" }, + { name = "mkdocs-material" }, + { name = "mkdocs-material-extensions" }, + { name = "mkdocstrings" }, + { name = "mkdocstrings-python" }, + { name = "pillow" }, + { name = "pyspelling" }, +] +lint = [ + { name = "black", marker = "implementation_name == 'cpython'" }, + { name = "flake8" }, + { name = "flake8-docstrings" }, + { name = "flake8-spellcheck" }, + { name = "fname8" }, + { name = "isort" }, + { name = "mypy", marker = "implementation_name == 'cpython'" }, + { name = "pep8-naming" }, + { name = "types-requests" }, +] +test = [ + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "bidict", specifier = ">=0.23,<1" }, + { name = "black", marker = "implementation_name == 'cpython' and extra == 'lint'", specifier = "==22.3.0" }, + { name = "cairosvg", marker = "extra == 'docs'", specifier = ">=2.7.0,<3" }, + { name = "click", specifier = ">=8.1.0,<9" }, + { name = "coincurve", specifier = ">=20.0.0,<21" }, + { name = "colorlog", specifier = ">=6.7.0,<7" }, + { name = "ethereum", git = "https://github.com/ethereum/execution-specs" }, + { name = "filelock", specifier = ">=3.15.1,<4" }, + { name = "flake8", marker = "extra == 'lint'", specifier = ">=6.1.0,<7" }, + { name = "flake8-docstrings", marker = "extra == 'lint'", specifier = ">=1.6,<2" }, + { name = "flake8-spellcheck", marker = "extra == 'lint'", specifier = ">=0.24,<0.25" }, + { name = "fname8", marker = "extra == 'lint'", specifier = ">=0.0.3" }, + { name = "gitpython", specifier = ">=3.1.31,<4" }, + { name = "hive-py", git = "https://github.com/marioevz/hive.py" }, + { name = "isort", marker = "extra == 'lint'", specifier = ">=5.8,<6" }, + { name = "mike", marker = "extra == 'docs'", specifier = ">=1.1.2,<2" }, + { name = "mkdocs", marker = "extra == 'docs'", specifier = ">=1.4.3,<2" }, + { name = "mkdocs-gen-files", marker = "extra == 'docs'", specifier = ">=0.5.0,<1" }, + { name = "mkdocs-git-authors-plugin", marker = "extra == 'docs'", specifier = ">=0.7.1,<1" }, + { name = "mkdocs-glightbox", marker = "extra == 'docs'", specifier = ">=0.3.4,<1" }, + { name = "mkdocs-literate-nav", marker = "extra == 'docs'", specifier = ">=0.6.0,<1" }, + { name = "mkdocs-material", marker = "extra == 'docs'", specifier = ">=9.1.14,<10" }, + { name = "mkdocs-material-extensions", marker = "extra == 'docs'", specifier = ">=1.1.1,<2" }, + { name = "mkdocstrings", marker = "extra == 'docs'", specifier = ">=0.21.2,<1" }, + { name = "mkdocstrings-python", marker = "extra == 'docs'", specifier = ">=1.0.0,<2" }, + { name = "mypy", marker = "implementation_name == 'cpython' and extra == 'lint'", specifier = "==0.991" }, + { name = "pep8-naming", marker = "extra == 'lint'", specifier = "==0.13.3" }, + { name = "pillow", marker = "extra == 'docs'", specifier = ">=10.0.1,<11" }, + { name = "pydantic", specifier = ">=2.8.0,<2.9" }, + { name = "pyjwt", specifier = ">=2.3.0,<3" }, + { name = "pyspelling", marker = "extra == 'docs'", specifier = ">=2.8.2,<3" }, + { name = "pytest", specifier = ">7.3.2,<8" }, + { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=4.1.0,<5" }, + { name = "pytest-html", specifier = ">=4.1.0,<5" }, + { name = "pytest-metadata", specifier = ">=3,<4" }, + { name = "pytest-xdist", specifier = ">=3.3.1,<4" }, + { name = "requests", specifier = ">=2.31.0,<3" }, + { name = "rich", specifier = ">=13.7.0,<14" }, + { name = "semver", specifier = ">=3.0.1,<4" }, + { name = "setuptools" }, + { name = "solc-select", specifier = ">=1.0.4" }, + { name = "tenacity", specifier = ">8.2.0,<9" }, + { name = "trie", specifier = ">=2.0.2,<3" }, + { name = "types-requests", marker = "extra == 'lint'" }, + { name = "types-setuptools" }, +] + +[[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 = "execnet" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size = 166524 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612 }, +] + +[[package]] +name = "filelock" +version = "3.15.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/08/dd/49e06f09b6645156550fb9aee9cc1e59aba7efbc972d665a1bd6ae0435d4/filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb", size = 18007 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/f0/48285f0262fe47103a4a45972ed2f9b93e4c80b8fd609fa98da78b2a5706/filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7", size = 16159 }, +] + +[[package]] +name = "flake8" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mccabe" }, + { name = "pycodestyle" }, + { name = "pyflakes" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cf/f8/bbe24f43695c0c480181e39ce910c2650c794831886ec46ddd7c40520e6a/flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23", size = 48767 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/24/bbf7175ffc47cb3d3e1eb523ddb23272968359dfcf2e1294707a2bf12fc4/flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5", size = 58260 }, +] + +[[package]] +name = "flake8-docstrings" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flake8" }, + { name = "pydocstyle" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/93/24/f839e3a06e18f4643ccb81370909a497297909f15106e6af2fecdef46894/flake8_docstrings-1.7.0.tar.gz", hash = "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af", size = 5995 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/7d/76a278fa43250441ed9300c344f889c7fb1817080c8fb8996b840bf421c2/flake8_docstrings-1.7.0-py2.py3-none-any.whl", hash = "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75", size = 4994 }, +] + +[[package]] +name = "flake8-spellcheck" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flake8" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/c8/c8e69da7ebe8953361de95814fe6e39ddb95bec02bd550c87b7a9d987f43/flake8-spellcheck-0.24.0.tar.gz", hash = "sha256:833c92222158b5dea74f858ccfb9f980b7c865fbd89cabc18447dadb07ec62e6", size = 337782 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/f7/860c3a53ece4848b78c9869906a39f3b1a918b2690ca997dd0425d29f629/flake8_spellcheck-0.24.0-py2.py3-none-any.whl", hash = "sha256:33d1727e4edb2b0cda3a78dee467d7bde53ff5a2a90056bc7d1764e0b060f331", size = 332403 }, +] + +[[package]] +name = "fname8" +version = "0.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/45/7a301ca31e67f44cf0a0e4bb683f8177b65b82f64246b60793b8776226d9/fname8-0.0.3.tar.gz", hash = "sha256:eeb7b8e117b60946eac41f334329c5d0edea52e7930d4fce9cd09e8cf8cf2eeb", size = 2765 } + +[[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 = "gitdb" +version = "4.0.11" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "smmap" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/0d/bbb5b5ee188dec84647a4664f3e11b06ade2bde568dbd489d9d64adef8ed/gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b", size = 394469 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/5b/8f0c4a5bb9fd491c277c21eff7ccae71b47d43c4446c9d0c6cff2fe8c2c4/gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4", size = 62721 }, +] + +[[package]] +name = "gitpython" +version = "3.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gitdb" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b6/a1/106fd9fa2dd989b6fb36e5893961f82992cf676381707253e0bf93eb1662/GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c", size = 214149 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/bd/cc3a402a6439c15c3d4294333e13042b915bbeab54edc457c723931fed3f/GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff", size = 207337 }, +] + +[[package]] +name = "griffe" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/92/79/cbe9be5ac67bfd87c48b5b2d2fa170bf8c33b38d8661d9d1849f038ab1f9/griffe-1.2.0.tar.gz", hash = "sha256:1c9f6ef7455930f3f9b0c4145a961c90385d1e2cbc496f7796fbff560ec60d31", size = 381349 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/0b/5caa5617b63535fe1e0abc23af92bd1e6df4bd3d5b72bfe2c675d4770235/griffe-1.2.0-py3-none-any.whl", hash = "sha256:a8b2fcb1ecdc5a412e646b0b4375eb20a5d2eac3a11dd8c10c56967a4097663c", size = 126930 }, +] + +[[package]] +name = "hexbytes" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/51/06836a542b773bfc60ab871fa08d4a7963e7df6754ca57169e2654287cc1/hexbytes-1.2.1.tar.gz", hash = "sha256:515f00dddf31053db4d0d7636dd16061c1d896c3109b8e751005db4ca46bcca7", size = 7722 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/c6/20f25ea73e4ceffb3eb4e38347f2992cb25e5ff6eb644d52e753a7a72f57/hexbytes-1.2.1-py3-none-any.whl", hash = "sha256:e64890b203a31f4a23ef11470ecfcca565beaee9198df623047df322b757471a", size = 5160 }, +] + +[[package]] +name = "hive-py" +version = "0.1.0" +source = { git = "https://github.com/marioevz/hive.py#1a546d06ae72e83c8d41fcaaba005c579ccd1d6a" } +dependencies = [ + { name = "requests" }, +] + +[[package]] +name = "html5lib" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/b6/b55c3f49042f1df3dcd422b7f224f939892ee94f22abcf503a9b7339eaf2/html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f", size = 272215 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/dd/a834df6482147d48e225a49515aabc28974ad5a4ca3215c18a882565b028/html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d", size = 112173 }, +] + +[[package]] +name = "idna" +version = "3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/ac/e349c5e6d4543326c6883ee9491e3921e0d07b55fdf3cce184b40d63e72a/idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603", size = 189467 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/7e/d71db821f177828df9dea8c42ac46473366f191be53080e552e628aad991/idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", size = 66894 }, +] + +[[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 = "isort" +version = "5.13.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310 }, +] + +[[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 = "lru-dict" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/63/21480e8ecc218b9b15672d194ea79da8a7389737c21d8406254306733cac/lru-dict-1.2.0.tar.gz", hash = "sha256:13c56782f19d68ddf4d8db0170041192859616514c706b126d0df2ec72a11bd7", size = 10895 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/37/b6f403da2849b239aa886837bd8cf8bf10e82479d46761b4d5d6b59a6385/lru_dict-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:de906e5486b5c053d15b7731583c25e3c9147c288ac8152a6d1f9bccdec72641", size = 9804 }, + { url = "https://files.pythonhosted.org/packages/e2/26/16b30966481724b1f101fa11ecdbe254bcada70358a66d88213045bb8c42/lru_dict-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604d07c7604b20b3130405d137cae61579578b0e8377daae4125098feebcb970", size = 29204 }, + { url = "https://files.pythonhosted.org/packages/62/df/166462dee2044aaa7430edb44d4e3c54a5a2aba32b4bf989351362677af5/lru_dict-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:203b3e78d03d88f491fa134f85a42919020686b6e6f2d09759b2f5517260c651", size = 30507 }, + { url = "https://files.pythonhosted.org/packages/77/e9/f4abc0be86b182ec26f226a15bc5f811b453b42f8d68d7f4dccf772fe07e/lru_dict-1.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:020b93870f8c7195774cbd94f033b96c14f51c57537969965c3af300331724fe", size = 27342 }, + { url = "https://files.pythonhosted.org/packages/e5/40/46779c4bfb68c0869a15c601d12c8861ccfab5cdeeac81444a84ce49914e/lru_dict-1.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1184d91cfebd5d1e659d47f17a60185bbf621635ca56dcdc46c6a1745d25df5c", size = 28854 }, + { url = "https://files.pythonhosted.org/packages/70/89/e0c57ab8cf31a5fe1e5bbf77ae01d52c2af3bead4262f41de83e97b09c03/lru_dict-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fc42882b554a86e564e0b662da47b8a4b32fa966920bd165e27bb8079a323bc1", size = 33359 }, + { url = "https://files.pythonhosted.org/packages/17/4e/b67ca93fb67e32e65f8fbe65b4e4171f9e840e3f7e8c75a727bad2f4002b/lru_dict-1.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:18ee88ada65bd2ffd483023be0fa1c0a6a051ef666d1cd89e921dcce134149f2", size = 32064 }, + { url = "https://files.pythonhosted.org/packages/bd/15/a961bc2e49c0427a2809454a118d794edc60a55233406852351dd0635160/lru_dict-1.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:756230c22257597b7557eaef7f90484c489e9ba78e5bb6ab5a5bcfb6b03cb075", size = 34924 }, + { url = "https://files.pythonhosted.org/packages/a1/40/bfb3da9ca6bcde088823896b2a88edb484438da7dbb945e5ac383023cc2d/lru_dict-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c4da599af36618881748b5db457d937955bb2b4800db891647d46767d636c408", size = 33188 }, + { url = "https://files.pythonhosted.org/packages/4e/63/36147a1845611613a92921f0f50778c8e41e72abceaf5f4da0b96c73ed76/lru_dict-1.2.0-cp310-cp310-win32.whl", hash = "sha256:35a142a7d1a4fd5d5799cc4f8ab2fff50a598d8cee1d1c611f50722b3e27874f", size = 11280 }, + { url = "https://files.pythonhosted.org/packages/cf/fb/1092131cde07ccaa0b06305ff7a3c5f1d00fc13cff7caf145193d0ff6ec3/lru_dict-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:6da5b8099766c4da3bf1ed6e7d7f5eff1681aff6b5987d1258a13bd2ed54f0c9", size = 12254 }, + { url = "https://files.pythonhosted.org/packages/a6/e2/26d77dc68963342c7dad7e6a186d0a7a8a598df3e43ec0f02fea61750c60/lru_dict-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b20b7c9beb481e92e07368ebfaa363ed7ef61e65ffe6e0edbdbaceb33e134124", size = 9845 }, + { url = "https://files.pythonhosted.org/packages/64/52/fcc07ba31ddcd64a0d1d8c4457062046c8b9797b1b24c12d84071f21a95a/lru_dict-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22147367b296be31cc858bf167c448af02435cac44806b228c9be8117f1bfce4", size = 30396 }, + { url = "https://files.pythonhosted.org/packages/07/14/224fdda47f9c91415ebb381a49fd420ec5f8a10dc31bdfa09081f14fcc45/lru_dict-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34a3091abeb95e707f381a8b5b7dc8e4ee016316c659c49b726857b0d6d1bd7a", size = 31735 }, + { url = "https://files.pythonhosted.org/packages/96/90/cda4bde886d05984c5146910462804006365eb9d47fd1bee5f0af9871f70/lru_dict-1.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:877801a20f05c467126b55338a4e9fa30e2a141eb7b0b740794571b7d619ee11", size = 28454 }, + { url = "https://files.pythonhosted.org/packages/2a/80/61628dfe0089181c7dbe231afc8326b54d3f71c0dacb695457f0d06302f8/lru_dict-1.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d3336e901acec897bcd318c42c2b93d5f1d038e67688f497045fc6bad2c0be7", size = 30144 }, + { url = "https://files.pythonhosted.org/packages/f8/c5/7f5f022ff817486b1a10247570ec65df3533189475f95ecc1ebeca30698d/lru_dict-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8dafc481d2defb381f19b22cc51837e8a42631e98e34b9e0892245cc96593deb", size = 35207 }, + { url = "https://files.pythonhosted.org/packages/89/59/6ec38dfc548bf62093a26e7ce9c6281a310391689bb0e9ab646cd2f54de2/lru_dict-1.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:87bbad3f5c3de8897b8c1263a9af73bbb6469fb90e7b57225dad89b8ef62cd8d", size = 33776 }, + { url = "https://files.pythonhosted.org/packages/de/45/ebc23ae4a6a0fba81d679b6d330c4297362f72b2e17d565f907caf74520c/lru_dict-1.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:25f9e0bc2fe8f41c2711ccefd2871f8a5f50a39e6293b68c3dec576112937aad", size = 36758 }, + { url = "https://files.pythonhosted.org/packages/32/7d/792b1c49f12ab745f07b63ccebb99f6dbe83d1dd9779df159b686cf4232a/lru_dict-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ae301c282a499dc1968dd633cfef8771dd84228ae9d40002a3ea990e4ff0c469", size = 35111 }, + { url = "https://files.pythonhosted.org/packages/23/e2/511117387f703ca1236ad2cb09702825266390811a4fb6a941adb401229f/lru_dict-1.2.0-cp311-cp311-win32.whl", hash = "sha256:c9617583173a29048e11397f165501edc5ae223504a404b2532a212a71ecc9ed", size = 11280 }, + { url = "https://files.pythonhosted.org/packages/2c/7a/5ea0f1200afee4f64335ea3698473f0bbc53ea5bae05f8e704187d0b54b6/lru_dict-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6b7a031e47421d4b7aa626b8c91c180a9f037f89e5d0a71c4bb7afcf4036c774", size = 12253 }, +] + +[[package]] +name = "lxml" +version = "5.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/6b/20c3a4b24751377aaa6307eb230b66701024012c29dd374999cc92983269/lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f", size = 3679318 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a1/ce/2789e39eddf2b13fac29878bfa465f0910eb6b0096e29090e5176bc8cf43/lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656", size = 8124570 }, + { url = "https://files.pythonhosted.org/packages/24/a8/f4010166a25d41715527129af2675981a50d3bbf7df09c5d9ab8ca24fbf9/lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d", size = 4413042 }, + { url = "https://files.pythonhosted.org/packages/41/a4/7e45756cecdd7577ddf67a68b69c1db0f5ddbf0c9f65021ee769165ffc5a/lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a", size = 5139213 }, + { url = "https://files.pythonhosted.org/packages/02/e2/ecf845b12323c92748077e1818b64e8b4dba509a4cb12920b3762ebe7552/lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8", size = 4838814 }, + { url = "https://files.pythonhosted.org/packages/12/91/619f9fb72cf75e9ceb8700706f7276f23995f6ad757e6d400fbe35ca4990/lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330", size = 5425084 }, + { url = "https://files.pythonhosted.org/packages/25/3b/162a85a8f0fd2a3032ec3f936636911c6e9523a8e263fffcfd581ce98b54/lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965", size = 4875993 }, + { url = "https://files.pythonhosted.org/packages/43/af/dd3f58cc7d946da6ae42909629a2b1d5dd2d1b583334d4af9396697d6863/lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22", size = 5012462 }, + { url = "https://files.pythonhosted.org/packages/69/c1/5ea46b2d4c98f5bf5c83fffab8a0ad293c9bc74df9ecfbafef10f77f7201/lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b", size = 4815288 }, + { url = "https://files.pythonhosted.org/packages/1d/51/a0acca077ad35da458f4d3f729ef98effd2b90f003440d35fc36323f8ae6/lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7", size = 5472435 }, + { url = "https://files.pythonhosted.org/packages/4d/6b/0989c9368986961a6b0f55b46c80404c4b758417acdb6d87bfc3bd5f4967/lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8", size = 4976354 }, + { url = "https://files.pythonhosted.org/packages/05/9e/87492d03ff604fbf656ed2bf3e2e8d28f5d58ea1f00ff27ac27b06509079/lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32", size = 5029973 }, + { url = "https://files.pythonhosted.org/packages/f9/cc/9ae1baf5472af88e19e2c454b3710c1be9ecafb20eb474eeabcd88a055d2/lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86", size = 4888837 }, + { url = "https://files.pythonhosted.org/packages/d2/10/5594ffaec8c120d75b17e3ad23439b740a51549a9b5fd7484b2179adfe8f/lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5", size = 5530555 }, + { url = "https://files.pythonhosted.org/packages/ea/9b/de17f05377c8833343b629905571fb06cff2028f15a6f58ae2267662e341/lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03", size = 5405314 }, + { url = "https://files.pythonhosted.org/packages/8a/b4/227be0f1f3cca8255925985164c3838b8b36e441ff0cc10c1d3c6bdba031/lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7", size = 5079303 }, + { url = "https://files.pythonhosted.org/packages/5c/ee/19abcebb7fc40319bb71cd6adefa1ad94d09b5660228715854d6cc420713/lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80", size = 3475126 }, + { url = "https://files.pythonhosted.org/packages/a1/35/183d32551447e280032b2331738cd850da435a42f850b71ebeaab42c1313/lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3", size = 3805065 }, + { url = "https://files.pythonhosted.org/packages/5c/a8/449faa2a3cbe6a99f8d38dcd51a3ee8844c17862841a6f769ea7c2a9cd0f/lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b", size = 8141056 }, + { url = "https://files.pythonhosted.org/packages/ac/8a/ae6325e994e2052de92f894363b038351c50ee38749d30cc6b6d96aaf90f/lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18", size = 4425238 }, + { url = "https://files.pythonhosted.org/packages/f8/fb/128dddb7f9086236bce0eeae2bfb316d138b49b159f50bc681d56c1bdd19/lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442", size = 5095197 }, + { url = "https://files.pythonhosted.org/packages/b4/f9/a181a8ef106e41e3086629c8bdb2d21a942f14c84a0e77452c22d6b22091/lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4", size = 4809809 }, + { url = "https://files.pythonhosted.org/packages/25/2f/b20565e808f7f6868aacea48ddcdd7e9e9fb4c799287f21f1a6c7c2e8b71/lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f", size = 5407593 }, + { url = "https://files.pythonhosted.org/packages/23/0e/caac672ec246d3189a16c4d364ed4f7d6bf856c080215382c06764058c08/lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e", size = 4866657 }, + { url = "https://files.pythonhosted.org/packages/67/a4/1f5fbd3f58d4069000522196b0b776a014f3feec1796da03e495cf23532d/lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c", size = 4967017 }, + { url = "https://files.pythonhosted.org/packages/ee/73/623ecea6ca3c530dd0a4ed0d00d9702e0e85cd5624e2d5b93b005fe00abd/lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16", size = 4810730 }, + { url = "https://files.pythonhosted.org/packages/1d/ce/fb84fb8e3c298f3a245ae3ea6221c2426f1bbaa82d10a88787412a498145/lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79", size = 5455154 }, + { url = "https://files.pythonhosted.org/packages/b1/72/4d1ad363748a72c7c0411c28be2b0dc7150d91e823eadad3b91a4514cbea/lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080", size = 4969416 }, + { url = "https://files.pythonhosted.org/packages/42/07/b29571a58a3a80681722ea8ed0ba569211d9bb8531ad49b5cacf6d409185/lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654", size = 5013672 }, + { url = "https://files.pythonhosted.org/packages/b9/93/bde740d5a58cf04cbd38e3dd93ad1e36c2f95553bbf7d57807bc6815d926/lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d", size = 4878644 }, + { url = "https://files.pythonhosted.org/packages/56/b5/645c8c02721d49927c93181de4017164ec0e141413577687c3df8ff0800f/lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763", size = 5511531 }, + { url = "https://files.pythonhosted.org/packages/85/3f/6a99a12d9438316f4fc86ef88c5d4c8fb674247b17f3173ecadd8346b671/lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec", size = 5402065 }, + { url = "https://files.pythonhosted.org/packages/80/8a/df47bff6ad5ac57335bf552babfb2408f9eb680c074ec1ba412a1a6af2c5/lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be", size = 5069775 }, + { url = "https://files.pythonhosted.org/packages/08/ae/e7ad0f0fbe4b6368c5ee1e3ef0c3365098d806d42379c46c1ba2802a52f7/lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9", size = 3474226 }, + { url = "https://files.pythonhosted.org/packages/c3/b5/91c2249bfac02ee514ab135e9304b89d55967be7e53e94a879b74eec7a5c/lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1", size = 3814971 }, + { url = "https://files.pythonhosted.org/packages/eb/6d/d1f1c5e40c64bf62afd7a3f9b34ce18a586a1cccbf71e783cd0a6d8e8971/lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859", size = 8171753 }, + { url = "https://files.pythonhosted.org/packages/bd/83/26b1864921869784355459f374896dcf8b44d4af3b15d7697e9156cb2de9/lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e", size = 4441955 }, + { url = "https://files.pythonhosted.org/packages/e0/d2/e9bff9fb359226c25cda3538f664f54f2804f4b37b0d7c944639e1a51f69/lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f", size = 5050778 }, + { url = "https://files.pythonhosted.org/packages/88/69/6972bfafa8cd3ddc8562b126dd607011e218e17be313a8b1b9cc5a0ee876/lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e", size = 4748628 }, + { url = "https://files.pythonhosted.org/packages/5d/ea/a6523c7c7f6dc755a6eed3d2f6d6646617cad4d3d6d8ce4ed71bfd2362c8/lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179", size = 5322215 }, + { url = "https://files.pythonhosted.org/packages/99/37/396fbd24a70f62b31d988e4500f2068c7f3fd399d2fd45257d13eab51a6f/lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a", size = 4813963 }, + { url = "https://files.pythonhosted.org/packages/09/91/e6136f17459a11ce1757df864b213efbeab7adcb2efa63efb1b846ab6723/lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3", size = 4923353 }, + { url = "https://files.pythonhosted.org/packages/1d/7c/2eeecf87c9a1fca4f84f991067c693e67340f2b7127fc3eca8fa29d75ee3/lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1", size = 4740541 }, + { url = "https://files.pythonhosted.org/packages/3b/ed/4c38ba58defca84f5f0d0ac2480fdcd99fc7ae4b28fc417c93640a6949ae/lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d", size = 5346504 }, + { url = "https://files.pythonhosted.org/packages/a5/22/bbd3995437e5745cb4c2b5d89088d70ab19d4feabf8a27a24cecb9745464/lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c", size = 4898077 }, + { url = "https://files.pythonhosted.org/packages/0a/6e/94537acfb5b8f18235d13186d247bca478fea5e87d224644e0fe907df976/lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99", size = 4946543 }, + { url = "https://files.pythonhosted.org/packages/8d/e8/4b15df533fe8e8d53363b23a41df9be907330e1fa28c7ca36893fad338ee/lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff", size = 4816841 }, + { url = "https://files.pythonhosted.org/packages/1a/e7/03f390ea37d1acda50bc538feb5b2bda6745b25731e4e76ab48fae7106bf/lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a", size = 5417341 }, + { url = "https://files.pythonhosted.org/packages/ea/99/d1133ab4c250da85a883c3b60249d3d3e7c64f24faff494cf0fd23f91e80/lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8", size = 5327539 }, + { url = "https://files.pythonhosted.org/packages/7d/ed/e6276c8d9668028213df01f598f385b05b55a4e1b4662ee12ef05dab35aa/lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d", size = 5012542 }, + { url = "https://files.pythonhosted.org/packages/36/88/684d4e800f5aa28df2a991a6a622783fb73cf0e46235cfa690f9776f032e/lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30", size = 3486454 }, + { url = "https://files.pythonhosted.org/packages/fc/82/ace5a5676051e60355bd8fb945df7b1ba4f4fb8447f2010fb816bfd57724/lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f", size = 3816857 }, + { url = "https://files.pythonhosted.org/packages/94/6a/42141e4d373903bfea6f8e94b2f554d05506dfda522ada5343c651410dc8/lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a", size = 8156284 }, + { url = "https://files.pythonhosted.org/packages/91/5e/fa097f0f7d8b3d113fb7312c6308af702f2667f22644441715be961f2c7e/lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd", size = 4432407 }, + { url = "https://files.pythonhosted.org/packages/2d/a1/b901988aa6d4ff937f2e5cfc114e4ec561901ff00660c3e56713642728da/lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51", size = 5048331 }, + { url = "https://files.pythonhosted.org/packages/30/0f/b2a54f48e52de578b71bbe2a2f8160672a8a5e103df3a78da53907e8c7ed/lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b", size = 4744835 }, + { url = "https://files.pythonhosted.org/packages/82/9d/b000c15538b60934589e83826ecbc437a1586488d7c13f8ee5ff1f79a9b8/lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002", size = 5316649 }, + { url = "https://files.pythonhosted.org/packages/e3/ee/ffbb9eaff5e541922611d2c56b175c45893d1c0b8b11e5a497708a6a3b3b/lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4", size = 4812046 }, + { url = "https://files.pythonhosted.org/packages/15/ff/7ff89d567485c7b943cdac316087f16b2399a8b997007ed352a1248397e5/lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492", size = 4918597 }, + { url = "https://files.pythonhosted.org/packages/c6/a3/535b6ed8c048412ff51268bdf4bf1cf052a37aa7e31d2e6518038a883b29/lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3", size = 4738071 }, + { url = "https://files.pythonhosted.org/packages/7a/8f/cbbfa59cb4d4fd677fe183725a76d8c956495d7a3c7f111ab8f5e13d2e83/lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4", size = 5342213 }, + { url = "https://files.pythonhosted.org/packages/5c/fb/db4c10dd9958d4b52e34d1d1f7c1f434422aeaf6ae2bbaaff2264351d944/lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367", size = 4893749 }, + { url = "https://files.pythonhosted.org/packages/f2/38/bb4581c143957c47740de18a3281a0cab7722390a77cc6e610e8ebf2d736/lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832", size = 4945901 }, + { url = "https://files.pythonhosted.org/packages/fc/d5/18b7de4960c731e98037bd48fa9f8e6e8f2558e6fbca4303d9b14d21ef3b/lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff", size = 4815447 }, + { url = "https://files.pythonhosted.org/packages/97/a8/cd51ceaad6eb849246559a8ef60ae55065a3df550fc5fcd27014361c1bab/lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd", size = 5411186 }, + { url = "https://files.pythonhosted.org/packages/89/c3/1e3dabab519481ed7b1fdcba21dcfb8832f57000733ef0e71cf6d09a5e03/lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb", size = 5324481 }, + { url = "https://files.pythonhosted.org/packages/b6/17/71e9984cf0570cd202ac0a1c9ed5c1b8889b0fc8dc736f5ef0ffb181c284/lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b", size = 5011053 }, + { url = "https://files.pythonhosted.org/packages/69/68/9f7e6d3312a91e30829368c2b3217e750adef12a6f8eb10498249f4e8d72/lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957", size = 3485634 }, + { url = "https://files.pythonhosted.org/packages/7d/db/214290d58ad68c587bd5d6af3d34e56830438733d0d0856c0275fde43652/lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d", size = 3814417 }, + { url = "https://files.pythonhosted.org/packages/99/f7/b73a431c8500565aa500e99e60b448d305eaf7c0b4c893c7c5a8a69cc595/lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c", size = 3925431 }, + { url = "https://files.pythonhosted.org/packages/db/48/4a206623c0d093d0e3b15f415ffb4345b0bdf661a3d0b15a112948c033c7/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a", size = 4216683 }, + { url = "https://files.pythonhosted.org/packages/54/47/577820c45dd954523ae8453b632d91e76da94ca6d9ee40d8c98dd86f916b/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005", size = 4326732 }, + { url = "https://files.pythonhosted.org/packages/68/de/96cb6d3269bc994b4f5ede8ca7bf0840f5de0a278bc6e50cb317ff71cafa/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce", size = 4218377 }, + { url = "https://files.pythonhosted.org/packages/a5/43/19b1ef6cbffa4244a217f95cc5f41a6cb4720fed33510a49670b03c5f1a0/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83", size = 4351237 }, + { url = "https://files.pythonhosted.org/packages/ba/b2/6a22fb5c0885da3b00e116aee81f0b829ec9ac8f736cd414b4a09413fc7d/lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba", size = 3487557 }, +] + +[[package]] +name = "markdown" +version = "3.7" +source = { registry = "https://pypi.org/simple" } +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 = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, +] + +[[package]] +name = "marko" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/07/ac/486e852e3d91e7ea69920b8913089f05c2a1ae3b639bf569e85c7b32e6fa/marko-1.0.2.tar.gz", hash = "sha256:bdf2e46de56f022f3930fb17f7bede90a8bc2ea27bdc68a887a024e1e5452b37", size = 28693 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/fc/5cfc266bf8a6240bb1d60dc36510831572f278896550727c9e7bee48ba9c/marko-1.0.2-py3-none-any.whl", hash = "sha256:ef40ef5853d5eae066024066764776fc6deb7d568adc16fbcad306d7bcf22a45", size = 34535 }, +] + +[[package]] +name = "markupsafe" +version = "2.1.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", size = 19384 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/54/ad5eb37bf9d51800010a74e4665425831a9db4e7c4e0fde4352e391e808e/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", size = 18206 }, + { url = "https://files.pythonhosted.org/packages/6a/4a/a4d49415e600bacae038c67f9fecc1d5433b9d3c71a4de6f33537b89654c/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", size = 14079 }, + { url = "https://files.pythonhosted.org/packages/0a/7b/85681ae3c33c385b10ac0f8dd025c30af83c78cec1c37a6aa3b55e67f5ec/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", size = 26620 }, + { url = "https://files.pythonhosted.org/packages/7c/52/2b1b570f6b8b803cef5ac28fdf78c0da318916c7d2fe9402a84d591b394c/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", size = 25818 }, + { url = "https://files.pythonhosted.org/packages/29/fe/a36ba8c7ca55621620b2d7c585313efd10729e63ef81e4e61f52330da781/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", size = 25493 }, + { url = "https://files.pythonhosted.org/packages/60/ae/9c60231cdfda003434e8bd27282b1f4e197ad5a710c14bee8bea8a9ca4f0/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", size = 30630 }, + { url = "https://files.pythonhosted.org/packages/65/dc/1510be4d179869f5dafe071aecb3f1f41b45d37c02329dfba01ff59e5ac5/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", size = 29745 }, + { url = "https://files.pythonhosted.org/packages/30/39/8d845dd7d0b0613d86e0ef89549bfb5f61ed781f59af45fc96496e897f3a/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", size = 30021 }, + { url = "https://files.pythonhosted.org/packages/c7/5c/356a6f62e4f3c5fbf2602b4771376af22a3b16efa74eb8716fb4e328e01e/MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", size = 16659 }, + { url = "https://files.pythonhosted.org/packages/69/48/acbf292615c65f0604a0c6fc402ce6d8c991276e16c80c46a8f758fbd30c/MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", size = 17213 }, + { url = "https://files.pythonhosted.org/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", size = 18219 }, + { url = "https://files.pythonhosted.org/packages/6b/cb/aed7a284c00dfa7c0682d14df85ad4955a350a21d2e3b06d8240497359bf/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", size = 14098 }, + { url = "https://files.pythonhosted.org/packages/1c/cf/35fe557e53709e93feb65575c93927942087e9b97213eabc3fe9d5b25a55/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", size = 29014 }, + { url = "https://files.pythonhosted.org/packages/97/18/c30da5e7a0e7f4603abfc6780574131221d9148f323752c2755d48abad30/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", size = 28220 }, + { url = "https://files.pythonhosted.org/packages/0c/40/2e73e7d532d030b1e41180807a80d564eda53babaf04d65e15c1cf897e40/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", size = 27756 }, + { url = "https://files.pythonhosted.org/packages/18/46/5dca760547e8c59c5311b332f70605d24c99d1303dd9a6e1fc3ed0d73561/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", size = 33988 }, + { url = "https://files.pythonhosted.org/packages/6d/c5/27febe918ac36397919cd4a67d5579cbbfa8da027fa1238af6285bb368ea/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", size = 32718 }, + { url = "https://files.pythonhosted.org/packages/f8/81/56e567126a2c2bc2684d6391332e357589a96a76cb9f8e5052d85cb0ead8/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", size = 33317 }, + { url = "https://files.pythonhosted.org/packages/00/0b/23f4b2470accb53285c613a3ab9ec19dc944eaf53592cb6d9e2af8aa24cc/MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", size = 16670 }, + { url = "https://files.pythonhosted.org/packages/b7/a2/c78a06a9ec6d04b3445a949615c4c7ed86a0b2eb68e44e7541b9d57067cc/MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", size = 17224 }, + { url = "https://files.pythonhosted.org/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", size = 18215 }, + { url = "https://files.pythonhosted.org/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", size = 14069 }, + { url = "https://files.pythonhosted.org/packages/51/b5/5d8ec796e2a08fc814a2c7d2584b55f889a55cf17dd1a90f2beb70744e5c/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", size = 29452 }, + { url = "https://files.pythonhosted.org/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", size = 28462 }, + { url = "https://files.pythonhosted.org/packages/2d/75/fd6cb2e68780f72d47e6671840ca517bda5ef663d30ada7616b0462ad1e3/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", size = 27869 }, + { url = "https://files.pythonhosted.org/packages/b0/81/147c477391c2750e8fc7705829f7351cf1cd3be64406edcf900dc633feb2/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", size = 33906 }, + { url = "https://files.pythonhosted.org/packages/8b/ff/9a52b71839d7a256b563e85d11050e307121000dcebc97df120176b3ad93/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", size = 32296 }, + { url = "https://files.pythonhosted.org/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", size = 33038 }, + { url = "https://files.pythonhosted.org/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", size = 16572 }, + { url = "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127 }, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350 }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, +] + +[[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 = "merlin-transcripts" +version = "0.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/1a/d9d3537b2eaebf270de21e0ceb1703c3c680c6979b901b4dcae3eddcbe2c/merlin_transcripts-0.1.1.tar.gz", hash = "sha256:ddc4da3cc3c209d6ab62fa8b5e8c3bc60ad86e8b2e9c5f9f687f4320ca33f145", size = 3682 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/37/f47d4da578421c384a7dc929be7a5ae2489cace9950669b7ac5cd733ae2b/merlin_transcripts-0.1.1-py3-none-any.whl", hash = "sha256:121ff93097000336f87bd8052413513ad0cace6c5a6a4831bd326cf9ad154c5d", size = 5125 }, +] + +[[package]] +name = "mike" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "mkdocs" }, + { name = "pyyaml" }, + { name = "verspec" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2d/76/2d89ba71dcf8e7a74b5e152fc8e86fe7c1f37bd86563fa8dea927f521425/mike-1.1.2.tar.gz", hash = "sha256:56c3f1794c2d0b5fdccfa9b9487beb013ca813de2e3ad0744724e9d34d40b77b", size = 28626 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/8a/f226f8c512a4e3ee36438613fde32d371262e985643d308850cf4bdaed15/mike-1.1.2-py3-none-any.whl", hash = "sha256:4c307c28769834d78df10f834f57f810f04ca27d248f80a75f49c6fa2d1527ca", size = 26933 }, +] + +[[package]] +name = "milagro-bls-binding" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/62/50284a3ebf16c63de11afc33eac15facc8a384f3d9f95174b776886822ef/milagro_bls_binding-1.9.0.tar.gz", hash = "sha256:43fb41b335b2a40ee21f2698c6ae27ed83921f5f6109443705f793c77d4b6d6e", size = 7026 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/8f/00be421467be0c346c6d56b455511722c2f164cd2242f0bbfbf99e9269d2/milagro_bls_binding-1.9.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:b2362f0d14318a3f44a3d1e186e2069eb25859cc4b9cae3e473505a28954803e", size = 445302 }, + { url = "https://files.pythonhosted.org/packages/a9/25/c5eb45d2e1e4f230b2d5e66301b67d108166601fba741011b50f84d200be/milagro_bls_binding-1.9.0-cp37-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:8800b9a8c61c20d1fdb5593b8e1940cbf6e521b454cc6f764fc22f026337651f", size = 818945 }, + { url = "https://files.pythonhosted.org/packages/df/f5/9bb967028fe6b9e83bd814504ded0eabb11fc49eb1ea7b26942922e5cf4f/milagro_bls_binding-1.9.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c47c5e45b30d0df02b65c2da4f9e10a49cc1a773f47796294663fc564ca56ee", size = 1160022 }, + { url = "https://files.pythonhosted.org/packages/d7/d3/7c459c5276d893ad542c4c8ee4f23c1e04e3b12622dd00c4a344a8d3d45a/milagro_bls_binding-1.9.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a28cbae598a01f76c5204a29b2d060c9aee8c66898e37c37b708aecc16d1b482", size = 1217504 }, + { url = "https://files.pythonhosted.org/packages/60/7a/42b86c783bffc7fe36bf5c415d37f3a93c09a03230869449d7379106273b/milagro_bls_binding-1.9.0-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5646113ffa12a43acda419341817cf3b1b327b9e81dfd2c2a98c6aa1b38422c0", size = 1150042 }, + { url = "https://files.pythonhosted.org/packages/13/c2/892e789a5418d2cd33a088c6d7637987ab14ccbd01bc18ae60caab0048cf/milagro_bls_binding-1.9.0-cp37-abi3-win32.whl", hash = "sha256:4d91da896d8de735c828dc1815d7dcaeeed9363c25a5d4f725ec3916672cbc79", size = 310512 }, + { url = "https://files.pythonhosted.org/packages/5d/d4/87ed4b9d1ec21723ac8161d8afba5695c7a39567593e0b509c7f59239ade/milagro_bls_binding-1.9.0-cp37-abi3-win_amd64.whl", hash = "sha256:d723eac25c1c5d8ebc9937a4eebcea40be1b2fff742dcf181d83e4ee59d2b12d", size = 294383 }, +] + +[[package]] +name = "mkdocs" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "ghp-import" }, + { 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/cc/6b/26b33cc8ad54e8bc0345cddc061c2c5c23e364de0ecd97969df23f95a673/mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512", size = 3888392 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/c0/930dcf5a3e96b9c8e7ad15502603fc61d495479699e2d2c381e3d37294d1/mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7", size = 3862264 }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/47/24/7d09b72b470d5dd33ed0c6722c7038ece494ab7dc5e72adbfeaf945276f6/mkdocs_autorefs-1.1.0.tar.gz", hash = "sha256:f2fd43b11f66284bd014f9b542a05c8ecbfaad4e0d7b30b68584788217b6c656", size = 36989 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/84/8e4dd669766f864482d2edcc44c7f07f4f91d73414c9a3e33b230a59f2cf/mkdocs_autorefs-1.1.0-py3-none-any.whl", hash = "sha256:492ac42f50214e81565e968f8cb0df9aba9d981542b9e7121b8f8ae9407fe6eb", size = 14417 }, +] + +[[package]] +name = "mkdocs-gen-files" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/85/2d634462fd59136197d3126ca431ffb666f412e3db38fd5ce3a60566303e/mkdocs_gen_files-0.5.0.tar.gz", hash = "sha256:4c7cf256b5d67062a788f6b1d035e157fc1a9498c2399be9af5257d4ff4d19bc", size = 7539 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/0f/1e55b3fd490ad2cecb6e7b31892d27cb9fc4218ec1dab780440ba8579e74/mkdocs_gen_files-0.5.0-py3-none-any.whl", hash = "sha256:7ac060096f3f40bd19039e7277dd3050be9a453c8ac578645844d4d91d7978ea", size = 8380 }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { 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-git-authors-plugin" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/03/99e18d62964d268eb9a866f42c9d53b43cde903a7fb436da85e396945a02/mkdocs_git_authors_plugin-0.9.0.tar.gz", hash = "sha256:6161f63b87064481a48d9ad01c23e43c3e758930c3a9cc167fe482909ceb9eac", size = 20268 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/ad/a6e0ce34a1d9abe35844cdc3a64028d3df7bfe24b143021f7fcaa26adfdd/mkdocs_git_authors_plugin-0.9.0-py3-none-any.whl", hash = "sha256:380730a05eeb947a7e84be05fdb1c5ae2a7bc70fd9f6eda941f187c87ae37052", size = 19204 }, +] + +[[package]] +name = "mkdocs-glightbox" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/5a/0bc456397ba0acc684b5b1daa4ca232ed717938fd37198251d8bcc4053bf/mkdocs-glightbox-0.4.0.tar.gz", hash = "sha256:392b34207bf95991071a16d5f8916d1d2f2cd5d5bb59ae2997485ccd778c70d9", size = 32010 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/72/b0c2128bb569c732c11ae8e49a777089e77d83c05946062caa19b841e6fb/mkdocs_glightbox-0.4.0-py3-none-any.whl", hash = "sha256:e0107beee75d3eb7380ac06ea2d6eac94c999eaa49f8c3cbab0e7be2ac006ccf", size = 31154 }, +] + +[[package]] +name = "mkdocs-literate-nav" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4d/f9/c48a04f3cf484f8016a343c1d7d99c3a1ef01dbb33ceabb1d02e0ecabda7/mkdocs_literate_nav-0.6.1.tar.gz", hash = "sha256:78a7ab6d878371728acb0cdc6235c9b0ffc6e83c997b037f4a5c6ff7cef7d759", size = 16437 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/3b/e00d839d3242844c77e248f9572dd34644a04300839a60fe7d6bf652ab19/mkdocs_literate_nav-0.6.1-py3-none-any.whl", hash = "sha256:e70bdc4a07050d32da79c0b697bd88e9a104cf3294282e9cb20eec94c6b0f401", size = 13182 }, +] + +[[package]] +name = "mkdocs-material" +version = "9.5.33" +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/73/d5/f393412423f92dde7a4d7b9b74f294c5f8589679132739bd3cd333099641/mkdocs_material-9.5.33.tar.gz", hash = "sha256:d23a8b5e3243c9b2f29cdfe83051104a8024b767312dc8fde05ebe91ad55d89d", size = 4107690 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/b1/1cebba96a01fa25299e9055bcd4c169f813f5cb73449194554a24bdda542/mkdocs_material-9.5.33-py3-none-any.whl", hash = "sha256:dbc79cf0fdc6e2c366aa987de8b0c9d4e2bb9f156e7466786ba2fd0f9bf7ffca", size = 8823286 }, +] + +[[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.25.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "platformdirs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/24/a6/d544fae9749b19e23fb590f6344f9eae3a312323065070b4874236bb0e04/mkdocstrings-0.25.2.tar.gz", hash = "sha256:5cf57ad7f61e8be3111a2458b4e49c2029c9cb35525393b179f9c916ca8042dc", size = 91796 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/86/ee2aef075cc9a62a4f087c3c3f4e3e8a8318afe05a92f8f8415f1bf1af64/mkdocstrings-0.25.2-py3-none-any.whl", hash = "sha256:9e2cda5e2e12db8bb98d21e3410f3f27f8faab685a24b03b06ba7daa5b92abfc", size = 29289 }, +] + +[[package]] +name = "mkdocstrings-python" +version = "1.10.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffe" }, + { name = "mkdocstrings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6b/ae/21b26c1fd62c8dd51ecefc8e848c14ca8f0dfdfeb903deeb20e86fb28ad1/mkdocstrings_python-1.10.8.tar.gz", hash = "sha256:5856a59cbebbb8deb133224a540de1ff60bded25e54d8beacc375bb133d39016", size = 161724 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/81/cda8afc58c7be82f0a7a9b54939e86f54eaad32a5b232afd6893ce3f00cb/mkdocstrings_python-1.10.8-py3-none-any.whl", hash = "sha256:bb12e76c8b071686617f824029cb1dfe0e9afe89f27fb3ad9a27f95f054dcd89", size = 108333 }, +] + +[[package]] +name = "mypy" +version = "0.991" +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/0e/5c/fbe112ca73d4c6a9e65336f48099c60800514d8949b4129c093a84a28dc8/mypy-0.991.tar.gz", hash = "sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06", size = 2688198 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/d0/81d47bffc80d0cff84174aab266adc3401e735e13c5613418e825c146986/mypy-0.991-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab", size = 18805560 }, + { url = "https://files.pythonhosted.org/packages/d7/f4/dcab9f3c5ed410caca1b9374dbb2b2caa778d225e32f174e266e20291edf/mypy-0.991-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d", size = 11117673 }, + { url = "https://files.pythonhosted.org/packages/87/ec/62fd00fa5d8ead3ecafed3eb99ee805911f41b11536c5940df1bcb2c845d/mypy-0.991-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6", size = 10023879 }, + { url = "https://files.pythonhosted.org/packages/39/05/7a7d58afc7d00e819e553ad2485a29141e14575e3b0c43b9da6f869ede4c/mypy-0.991-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc9ec663ed6c8f15f4ae9d3c04c989b744436c16d26580eaa760ae9dd5d662eb", size = 18209901 }, + { url = "https://files.pythonhosted.org/packages/80/23/76e56e004acca691b4da4086a8c38bd67b7ae73536848dcab76cfed5c188/mypy-0.991-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4307270436fd7694b41f913eb09210faff27ea4979ecbcd849e57d2da2f65305", size = 19680479 }, + { url = "https://files.pythonhosted.org/packages/f3/1d/cc67a674f1cd7f1c10619487a4245185f6f8f14cbd685b60709318e9ac27/mypy-0.991-cp310-cp310-win_amd64.whl", hash = "sha256:901c2c269c616e6cb0998b33d4adbb4a6af0ac4ce5cd078afd7bc95830e62c1c", size = 8670519 }, + { url = "https://files.pythonhosted.org/packages/b8/ab/aa2e02fce8ee8885fe98ee2a0549290e9de5caa28febc0cf243bfab020e7/mypy-0.991-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372", size = 18600640 }, + { url = "https://files.pythonhosted.org/packages/28/9c/e1805f2fea93a92671f33b00dd577119f37e4a8b859d6f6ea62d3e9129fa/mypy-0.991-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c8cd4fb70e8584ca1ed5805cbc7c017a3d1a29fb450621089ffed3e99d1857f", size = 11004105 }, + { url = "https://files.pythonhosted.org/packages/df/bb/3cf400e05e30939a0fc58b34e0662d8abe8e206464665065b56cf2ca9a62/mypy-0.991-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:209ee89fbb0deed518605edddd234af80506aec932ad28d73c08f1400ef80a33", size = 9939717 }, + { url = "https://files.pythonhosted.org/packages/14/05/5a4206e269268f4aecb1096bf2375a231c959987ccf3e31313221b8bc153/mypy-0.991-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37bd02ebf9d10e05b00d71302d2c2e6ca333e6c2a8584a98c00e038db8121f05", size = 18068884 }, + { url = "https://files.pythonhosted.org/packages/4b/98/125e5d14222de8e92f44314f8df21a9c351b531b37c551526acd67486a7d/mypy-0.991-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:26efb2fcc6b67e4d5a55561f39176821d2adf88f2745ddc72751b7890f3194ad", size = 19451243 }, + { url = "https://files.pythonhosted.org/packages/89/76/7159258fdbf26a5ceef100b80a82d2f79b9066725a5daeb6383a8f773910/mypy-0.991-cp311-cp311-win_amd64.whl", hash = "sha256:3a700330b567114b673cf8ee7388e949f843b356a73b5ab22dd7cff4742a5297", size = 8666646 }, + { url = "https://files.pythonhosted.org/packages/e7/a1/c503a15ad69ff133a76c159b8287f0eadc1f521d9796bf81f935886c98f6/mypy-0.991-py3-none-any.whl", hash = "sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb", size = 2307767 }, +] + +[[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 = "packaging" +version = "24.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, +] + +[[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 = "pep8-naming" +version = "0.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flake8" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/c0/0db8b2867395a9a137e86af8bdf5a566e41d9c6453e509cd3042419ae29e/pep8-naming-0.13.3.tar.gz", hash = "sha256:1705f046dfcd851378aac3be1cd1551c7c1e5ff363bacad707d43007877fa971", size = 16129 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/48/9533518e0394fb858ac2b4b55fe18f24aa33c87c943f691336ec842d9728/pep8_naming-0.13.3-py3-none-any.whl", hash = "sha256:1a86b8c71a03337c97181917e2b472f0f5e4ccb06844a0d6f0a33522549e7a80", size = 8490 }, +] + +[[package]] +name = "pillow" +version = "10.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271 }, + { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658 }, + { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075 }, + { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808 }, + { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290 }, + { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163 }, + { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100 }, + { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880 }, + { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218 }, + { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487 }, + { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219 }, + { url = "https://files.pythonhosted.org/packages/a7/62/c9449f9c3043c37f73e7487ec4ef0c03eb9c9afc91a92b977a67b3c0bbc5/pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c", size = 3509265 }, + { url = "https://files.pythonhosted.org/packages/f4/5f/491dafc7bbf5a3cc1845dc0430872e8096eb9e2b6f8161509d124594ec2d/pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be", size = 3375655 }, + { url = "https://files.pythonhosted.org/packages/73/d5/c4011a76f4207a3c151134cd22a1415741e42fa5ddecec7c0182887deb3d/pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3", size = 4340304 }, + { url = "https://files.pythonhosted.org/packages/ac/10/c67e20445a707f7a610699bba4fe050583b688d8cd2d202572b257f46600/pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6", size = 4452804 }, + { url = "https://files.pythonhosted.org/packages/a9/83/6523837906d1da2b269dee787e31df3b0acb12e3d08f024965a3e7f64665/pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe", size = 4365126 }, + { url = "https://files.pythonhosted.org/packages/ba/e5/8c68ff608a4203085158cff5cc2a3c534ec384536d9438c405ed6370d080/pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319", size = 4533541 }, + { url = "https://files.pythonhosted.org/packages/f4/7c/01b8dbdca5bc6785573f4cee96e2358b0918b7b2c7b60d8b6f3abf87a070/pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d", size = 4471616 }, + { url = "https://files.pythonhosted.org/packages/c8/57/2899b82394a35a0fbfd352e290945440e3b3785655a03365c0ca8279f351/pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696", size = 4600802 }, + { url = "https://files.pythonhosted.org/packages/4d/d7/a44f193d4c26e58ee5d2d9db3d4854b2cfb5b5e08d360a5e03fe987c0086/pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496", size = 2235213 }, + { url = "https://files.pythonhosted.org/packages/c1/d0/5866318eec2b801cdb8c82abf190c8343d8a1cd8bf5a0c17444a6f268291/pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91", size = 2554498 }, + { url = "https://files.pythonhosted.org/packages/d4/c8/310ac16ac2b97e902d9eb438688de0d961660a87703ad1561fd3dfbd2aa0/pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22", size = 2243219 }, + { url = "https://files.pythonhosted.org/packages/05/cb/0353013dc30c02a8be34eb91d25e4e4cf594b59e5a55ea1128fde1e5f8ea/pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94", size = 3509350 }, + { url = "https://files.pythonhosted.org/packages/e7/cf/5c558a0f247e0bf9cec92bff9b46ae6474dd736f6d906315e60e4075f737/pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597", size = 3374980 }, + { url = "https://files.pythonhosted.org/packages/84/48/6e394b86369a4eb68b8a1382c78dc092245af517385c086c5094e3b34428/pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80", size = 4343799 }, + { url = "https://files.pythonhosted.org/packages/3b/f3/a8c6c11fa84b59b9df0cd5694492da8c039a24cd159f0f6918690105c3be/pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca", size = 4459973 }, + { url = "https://files.pythonhosted.org/packages/7d/1b/c14b4197b80150fb64453585247e6fb2e1d93761fa0fa9cf63b102fde822/pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef", size = 4370054 }, + { url = "https://files.pythonhosted.org/packages/55/77/40daddf677897a923d5d33329acd52a2144d54a9644f2a5422c028c6bf2d/pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a", size = 4539484 }, + { url = "https://files.pythonhosted.org/packages/40/54/90de3e4256b1207300fb2b1d7168dd912a2fb4b2401e439ba23c2b2cabde/pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b", size = 4477375 }, + { url = "https://files.pythonhosted.org/packages/13/24/1bfba52f44193860918ff7c93d03d95e3f8748ca1de3ceaf11157a14cf16/pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9", size = 4608773 }, + { url = "https://files.pythonhosted.org/packages/55/04/5e6de6e6120451ec0c24516c41dbaf80cce1b6451f96561235ef2429da2e/pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42", size = 2235690 }, + { url = "https://files.pythonhosted.org/packages/74/0a/d4ce3c44bca8635bd29a2eab5aa181b654a734a29b263ca8efe013beea98/pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a", size = 2554951 }, + { url = "https://files.pythonhosted.org/packages/b5/ca/184349ee40f2e92439be9b3502ae6cfc43ac4b50bc4fc6b3de7957563894/pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9", size = 2243427 }, + { url = "https://files.pythonhosted.org/packages/c3/00/706cebe7c2c12a6318aabe5d354836f54adff7156fd9e1bd6c89f4ba0e98/pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3", size = 3525685 }, + { url = "https://files.pythonhosted.org/packages/cf/76/f658cbfa49405e5ecbfb9ba42d07074ad9792031267e782d409fd8fe7c69/pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb", size = 3374883 }, + { url = "https://files.pythonhosted.org/packages/46/2b/99c28c4379a85e65378211971c0b430d9c7234b1ec4d59b2668f6299e011/pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70", size = 4339837 }, + { url = "https://files.pythonhosted.org/packages/f1/74/b1ec314f624c0c43711fdf0d8076f82d9d802afd58f1d62c2a86878e8615/pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be", size = 4455562 }, + { url = "https://files.pythonhosted.org/packages/4a/2a/4b04157cb7b9c74372fa867096a1607e6fedad93a44deeff553ccd307868/pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0", size = 4366761 }, + { url = "https://files.pythonhosted.org/packages/ac/7b/8f1d815c1a6a268fe90481232c98dd0e5fa8c75e341a75f060037bd5ceae/pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc", size = 4536767 }, + { url = "https://files.pythonhosted.org/packages/e5/77/05fa64d1f45d12c22c314e7b97398ffb28ef2813a485465017b7978b3ce7/pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a", size = 4477989 }, + { url = "https://files.pythonhosted.org/packages/12/63/b0397cfc2caae05c3fb2f4ed1b4fc4fc878f0243510a7a6034ca59726494/pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309", size = 4610255 }, + { url = "https://files.pythonhosted.org/packages/7b/f9/cfaa5082ca9bc4a6de66ffe1c12c2d90bf09c309a5f52b27759a596900e7/pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060", size = 2235603 }, + { url = "https://files.pythonhosted.org/packages/01/6a/30ff0eef6e0c0e71e55ded56a38d4859bf9d3634a94a88743897b5f96936/pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea", size = 2554972 }, + { url = "https://files.pythonhosted.org/packages/48/2c/2e0a52890f269435eee38b21c8218e102c621fe8d8df8b9dd06fabf879ba/pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", size = 2243375 }, + { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889 }, + { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160 }, + { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020 }, + { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539 }, + { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125 }, + { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373 }, + { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661 }, +] + +[[package]] +name = "platformdirs" +version = "4.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/52/0763d1d976d5c262df53ddda8d8d4719eedf9594d046f117c25a27261a19/platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3", size = 20916 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/13/2aa1f0e1364feb2c9ef45302f387ac0bd81484e9c9a4c5688a322fbdfd08/platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", size = 18146 }, +] + +[[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 = "py-arkworks-bls12381" +version = "0.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/bf/00e5ed8360183b33189dc9380a9a9b7d820a32feee7533e0e92279479307/py_arkworks_bls12381-0.3.4.tar.gz", hash = "sha256:93a86d24b0b07722c9449cef523e977c2018ec7673accfac25334694f40f3848", size = 13915 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/bf/aaed379d8bb5b4f1d6c54f097762046dd47931e857c0a2d48c8deb3d1d62/py_arkworks_bls12381-0.3.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d5705c69c01190df29b4ec22237f34e04e21a864ccbd1561d5a2782269ace2fd", size = 473308 }, + { url = "https://files.pythonhosted.org/packages/f8/36/3cd16eb7d51465182e2ae33d2a4e0301d0dee00378b8faa1d183805e7f6b/py_arkworks_bls12381-0.3.4-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7b77d0e84204a27c0cd2755084cdba147aabdd914e31f3e1d9bf39de8e04d1eb", size = 550476 }, + { url = "https://files.pythonhosted.org/packages/db/68/0cd8fe98f14b1b0f587d1bced5f65d9ea5c1491955b421086363282fbcf5/py_arkworks_bls12381-0.3.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4b861f26e3a32e623d115cc12ce9da637c4ad85717fef02bfe949de32fc31aab", size = 460875 }, + { url = "https://files.pythonhosted.org/packages/ce/47/43e8712b2b15c4f296e5ce87bbddcb8bd96c98a2349e34d5c312a40800fc/py_arkworks_bls12381-0.3.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fddec2702093c4505fa2bb6fb754efe54692502e556bc03d2be6a369dfe20bea", size = 1398863 }, + { url = "https://files.pythonhosted.org/packages/95/97/c0944eb5a21847dad16f8937292be5e6da1fc55f7c6fb0436c003a6bc1ba/py_arkworks_bls12381-0.3.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f5b4bc1e0326be10ea1c522c8eecd638723116c9838703bf245fc1b55b5777f", size = 1319369 }, + { url = "https://files.pythonhosted.org/packages/7c/b6/031c23e687fd95c91fb4353c293b19f4f4c2c14c5e87e8f3399b4a610712/py_arkworks_bls12381-0.3.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f82cd27fa579f3911154b731bc6860f38fa49e3d4fe509e971fbb56b2c17b2eb", size = 1399570 }, + { url = "https://files.pythonhosted.org/packages/ec/67/442b2616baa70c3813ce886408571d2a115f5f050587d90ec1bf0524df51/py_arkworks_bls12381-0.3.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2b529a3c539a53acf9a233bf9b7b40828415c2cf1f1b9fb9d2143b080a88355", size = 651404 }, + { url = "https://files.pythonhosted.org/packages/77/23/6dd0e56b6d7ba8570c24660afd57dee743331b9c0d8632d0cd0177795d65/py_arkworks_bls12381-0.3.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ba5245469fea19deeab059c4fb49d7332ee16659b1a0c85692c786e032d3957", size = 1470292 }, + { url = "https://files.pythonhosted.org/packages/47/06/ca32eb47e4da5e76ee619b53aea9f63052f73ee4e7de67bd9e0cd33434af/py_arkworks_bls12381-0.3.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d82ef2604fed956953c1947210248ed452f2be03d4490e27e7c9438b31495a8", size = 1520650 }, + { url = "https://files.pythonhosted.org/packages/5f/b7/a047f2d051e9ba13df4db5ea5701cf2d74f273ff9084035e9ddf50beed0d/py_arkworks_bls12381-0.3.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7414ac0fd29abe39ad2b8b78fb80bc52ca4527cbca24f28db9064c073b003062", size = 1376601 }, + { url = "https://files.pythonhosted.org/packages/9e/5b/f47facfb5bd741eb9b927279f8d851d2be4744180390ca504f30289850db/py_arkworks_bls12381-0.3.4-cp310-none-win32.whl", hash = "sha256:2a424c1f07f23c385b242699370cc3cabec62c0c4d6909487b932789319d9433", size = 324531 }, + { url = "https://files.pythonhosted.org/packages/20/39/bc0150061941da7e41aaae9d6596152a0656a2d3c0ea51d70fb9d93f9add/py_arkworks_bls12381-0.3.4-cp310-none-win_amd64.whl", hash = "sha256:e318e5df82bad081c37babd929126a5c8f83e04009afcb4bf8e8a20c1d8f1abd", size = 377620 }, + { url = "https://files.pythonhosted.org/packages/4a/60/3945d01b8b6b273a38518ea471f7da2251c713514068caf2c50afd387ed3/py_arkworks_bls12381-0.3.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3e30fccbbbcd60d5797727ab335a15cd31fe819cc2391e1705ca1bf601a81b0a", size = 473309 }, + { url = "https://files.pythonhosted.org/packages/d4/a7/b367e1f27da0d2621726956f58c3ee545ef5beace22d4f9d9b3fcea07fe0/py_arkworks_bls12381-0.3.4-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:ce3d8bc5b495881d783ac46025c47fcb6e4d38deb3e5f32bb572f2a370099183", size = 550474 }, + { url = "https://files.pythonhosted.org/packages/71/8d/a0ff1c34f9162b2154cd559c42c97db0c15d32c292c644b4761038a38aff/py_arkworks_bls12381-0.3.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e1d837cd246efe8ded815e8a8de461c87772dc1a0359eb4fce8b815d473e94b4", size = 460872 }, + { url = "https://files.pythonhosted.org/packages/27/1f/02332d047a7ce7dc97602ff67146aace009df4f066e4de51bd01722c8b7b/py_arkworks_bls12381-0.3.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:55a21207599bba40524a4791ca6538513cd212c7cb7466f13f95b3f401c6ff94", size = 1398864 }, + { url = "https://files.pythonhosted.org/packages/53/ca/c45da7669e56cfbd97f31f5cfcbcafdf5db2864164940df0acafe44885fb/py_arkworks_bls12381-0.3.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19e036b37fa07d824f2b4d289bae5ee4b820b3702fd6cb01716587a5f43ab3be", size = 1319372 }, + { url = "https://files.pythonhosted.org/packages/62/ca/2cc96e49da70424f27ef7bfe277c1ba4ed684813dcc4975ee5b203af281f/py_arkworks_bls12381-0.3.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d6ba0d216fd7d6a62f8743c8f079f69db473ab6058112d78e60bb46aa857ffe", size = 1399571 }, + { url = "https://files.pythonhosted.org/packages/3b/00/6247729dfd310f6847eec06e8f54956045d28adc4f11aa8a87a901b23b0c/py_arkworks_bls12381-0.3.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:130af57c7572ba6fb40e5cb82e308ac6a268611084915ce15350f4451674d505", size = 651403 }, + { url = "https://files.pythonhosted.org/packages/55/1e/65a2e0d98a5b3acc33777672760ddf56d2add93bb0f4a62e09dbe9aff751/py_arkworks_bls12381-0.3.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66c03ef4a8841d111c76e86d9c86ce73474c1d08d025c569567352cd5745aef2", size = 1470291 }, + { url = "https://files.pythonhosted.org/packages/ea/8c/851e1843103716defea1133c24f21860a997c0980fcbb34b630ed7c34b15/py_arkworks_bls12381-0.3.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a81bce857ea7db3fd7a5e76a607cd794b36a78aea6cb18c710f9b162bac46b83", size = 1520656 }, + { url = "https://files.pythonhosted.org/packages/89/ca/2cbeb8dc2fdaa6d2785e21eb1083840f9e7102fd159e699c0899d1a26884/py_arkworks_bls12381-0.3.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a03209f97d6732c828a2383ab022c763d94530fad6b61468e1c5e149c5fa5710", size = 1376599 }, + { url = "https://files.pythonhosted.org/packages/a1/c5/79d4e55e54e53f0f457a5dfb55de5dfddf49a9f5ac33b6bbc6e379461140/py_arkworks_bls12381-0.3.4-cp311-none-win32.whl", hash = "sha256:f4c80957d3dd4bc3a045e78b139e06f7eb82004297b7c56faa505d16fb7ce650", size = 324536 }, + { url = "https://files.pythonhosted.org/packages/1b/c1/72a60cb6b5e95b2bbfae4f2b1f9ec9554c7db54abad6a0e9b4a2a4ec07fe/py_arkworks_bls12381-0.3.4-cp311-none-win_amd64.whl", hash = "sha256:6267bb2d5ae9ce0953fe50d8316538e1e3f2af642a19621ee23f53dfda52e900", size = 377622 }, + { url = "https://files.pythonhosted.org/packages/1d/ce/3b73e1055e6ca2480c4439e82544aebf7f2a03842579c654f3b06670f895/py_arkworks_bls12381-0.3.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c20ca32f3cd8d2c3a7f63869aa96aba727e5b04f3914658d8fc86c13cad836ca", size = 472782 }, + { url = "https://files.pythonhosted.org/packages/ea/db/71ac5fc3705a613fb7583defd139daa241451604080de686bb51b2171d64/py_arkworks_bls12381-0.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fa4a0066b15c2b8b0e9d257ba9aa3d1a52fab517851f54a92bb07adb2bcacbab", size = 449564 }, + { url = "https://files.pythonhosted.org/packages/74/f8/a3143cbc96390fd3246a70f332ab9c0eacf92a14d9ebdd92b3b67cd553f8/py_arkworks_bls12381-0.3.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72cb392eeecffd28e43585c104da005999be485e5a763ebff271679560e0d36a", size = 1319400 }, + { url = "https://files.pythonhosted.org/packages/e2/7d/086f1cda9f4bf77f1f5f8351202fd75e0f4fe0abb67360e4b6915f110a9e/py_arkworks_bls12381-0.3.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4b8f74d745a744050b1793e04d1c08e601cd0f9ff74f4c7bf25a340553548f3", size = 651530 }, + { url = "https://files.pythonhosted.org/packages/9c/45/4887b6a0f8971cbed3856f368121a34cf1de2941c374af8de68658f9a19d/py_arkworks_bls12381-0.3.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7d87f93ccdc6ac07c3c9cfdc0700980b39ca633216769ea1f7659f320a8e5514", size = 1470327 }, + { url = "https://files.pythonhosted.org/packages/ce/1c/013d727a3e0ac0ddda68577feaa77ee7df0ec0dfbedf97cc0fceeada9767/py_arkworks_bls12381-0.3.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2842dae251f9d52b2f51bdfc7c01165905ebd55bafda9dcebde501fad913fa8b", size = 1520653 }, + { url = "https://files.pythonhosted.org/packages/10/75/9765de350716b4486383b6b12a2d5500af6ad143b7ea40701949993cbbb1/py_arkworks_bls12381-0.3.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4403fdf7f66ba1d16ffa94f649c5a30594de465f623ed3f884c4bf558ca9c5da", size = 517186 }, + { url = "https://files.pythonhosted.org/packages/0c/20/e882ca1064cd7361893e57b4088b000d9b5fba69940bc74f950b822796c6/py_arkworks_bls12381-0.3.4-cp312-none-win32.whl", hash = "sha256:52cf76462e52b2f2a54b7952a35703364654e6ea56ca316431cd398b36508f51", size = 384625 }, + { url = "https://files.pythonhosted.org/packages/5b/ad/7d72a96479603f56e2a5333673f1780ad9437812717dbd47706a33b8e71e/py_arkworks_bls12381-0.3.4-cp312-none-win_amd64.whl", hash = "sha256:0685e4b78f2e8f1d71d988998a94648947b63b03255637ee57e6f2620ba0010f", size = 341572 }, + { url = "https://files.pythonhosted.org/packages/73/6e/52f8e00a50cfa9c921fe965c6478a7d16c7de593192b4fbd3186bd68832b/py_arkworks_bls12381-0.3.4-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4804f29500384dc3886e2caab2d86a319adb51b481138196dca9007892122410", size = 650427 }, + { url = "https://files.pythonhosted.org/packages/82/09/b52f2cb32e141c9b111044f3046ff5ee24b194f072e61122e667efd1e5b9/py_arkworks_bls12381-0.3.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e3c1a97986bd7e70a0394f697ca3111f9816255cd0e6e8e280bdeb820cb354f", size = 517565 }, +] + +[[package]] +name = "py-ecc" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cached-property" }, + { name = "eth-typing" }, + { name = "eth-utils" }, + { name = "mypy-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/e3/12234aef5f578457f10e1cdd28737445b5918c1cf4049da5d34587647fa1/py_ecc-6.0.0.tar.gz", hash = "sha256:3fc8a79e38975e05dc443d25783fd69212a1ca854cc0efef071301a8f7d6ce1d", size = 30935 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/c5/1103d24bd740254fc89aad727d09e5fd73d6d89fb555da6e0a9d92ec009e/py_ecc-6.0.0-py3-none-any.whl", hash = "sha256:54e8aa4c30374fa62d582c599a99f352c153f2971352171318bd6910a643be0b", size = 43419 }, +] + +[[package]] +name = "pycodestyle" +version = "2.11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/8f/fa09ae2acc737b9507b5734a9aec9a2b35fa73409982f57db1b42f8c3c65/pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f", size = 38974 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/90/a998c550d0ddd07e38605bb5c455d00fcc177a800ff9cc3dafdcb3dd7b56/pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67", size = 31132 }, +] + +[[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.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/e4/a8e8056a59c39f8c9ddd11d3bc3e1a67493abe746df727e531f66ecede9e/pycryptodome-3.15.0.tar.gz", hash = "sha256:9135dddad504592bcc18b0d2d95ce86c3a5ea87ec6447ef25cfedea12d6018b8", size = 4547210 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/dc/e5bb825eb7348773b77ace0d977f549af851c1d8300f1ba60119e88ba715/pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676", size = 1558258 }, + { url = "https://files.pythonhosted.org/packages/2e/6f/27fbd8f3fd8b48feba2b4226f7f8d23af7755c54957fccc3fe6f44b764cf/pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667", size = 2469207 }, + { url = "https://files.pythonhosted.org/packages/b1/54/ad3e2e07a5a7ceb926971398f7e3a0eeee85b6e1d3e658df8f71a4497daa/pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88", size = 2303310 }, + { url = "https://files.pythonhosted.org/packages/c5/b4/526dd68f6c8ff6b785d7a08da7a6bba5646cced508454f1d1ab948e6b737/pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d", size = 2469209 }, + { url = "https://files.pythonhosted.org/packages/7d/be/e3e56f7f92bebf506aec486eb71d91952d2e9faf5e10872a89931db4120f/pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2", size = 2303313 }, + { url = "https://files.pythonhosted.org/packages/35/5b/ba592bfd0d3bad9450645b751c132cf1028dc111ae699fd8e70808414941/pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e", size = 1589891 }, + { url = "https://files.pythonhosted.org/packages/02/fa/f83072580377dcdf4d2ff3c7d25d225790302a86cfd1e9eb2c2832740135/pycryptodome-3.15.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:50ca7e587b8e541eb6c192acf92449d95377d1f88908c0a32ac5ac2703ebe28b", size = 2032482 }, + { url = "https://files.pythonhosted.org/packages/55/60/28d873c1efe46cf62494a0393fe34e4757821123fb1af9c45be3b2eeba8a/pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1", size = 1877649 }, + { url = "https://files.pythonhosted.org/packages/00/07/5a262e3213a9358e2f7caf9080aa8a984f44bf4aee84592dfb965dd34355/pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9", size = 1941787 }, + { url = "https://files.pythonhosted.org/packages/bb/7a/0e51d1dc253d0571106009b94762b8ab5a7c905079c354247b721ae1f198/pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f", size = 1536248 }, + { url = "https://files.pythonhosted.org/packages/9b/e8/628f92b38ee4475d7b316d04c2913d397cdcc3f3a873bdbea10a438ba9fe/pycryptodome-3.15.0-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:ff287bcba9fbeb4f1cccc1f2e90a08d691480735a611ee83c80a7d74ad72b9d9", size = 1613313 }, + { url = "https://files.pythonhosted.org/packages/b1/6c/4ee93e2e863e95caffc5a356b867e86f5596f4e38cddb43848412dd69176/pycryptodome-3.15.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:60b4faae330c3624cc5a546ba9cfd7b8273995a15de94ee4538130d74953ec2e", size = 1613316 }, + { url = "https://files.pythonhosted.org/packages/c8/03/1f745c158299000664a6fb5c0b28d5359837b05b4ba1f5a37645da5cad4d/pycryptodome-3.15.0-pp27-pypy_73-win32.whl", hash = "sha256:a8f06611e691c2ce45ca09bbf983e2ff2f8f4f87313609d80c125aff9fad6e7f", size = 1681598 }, +] + +[[package]] +name = "pydantic" +version = "2.8.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8c/99/d0a5dca411e0a017762258013ba9905cd6e7baa9a3fd1fe8b6529472902e/pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a", size = 739834 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/fa/b7f815b8c9ad021c07f88875b601222ef5e70619391ade4a49234d12d278/pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8", size = 423875 }, +] + +[[package]] +name = "pydantic-core" +version = "2.20.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/12/e3/0d5ad91211dba310f7ded335f4dad871172b9cc9ce204f5a56d76ccd6247/pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4", size = 388371 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/9d/f30f080f745682e762512f3eef1f6e392c7d74a102e6e96de8a013a5db84/pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3", size = 1837257 }, + { url = "https://files.pythonhosted.org/packages/f2/89/77e7aebdd4a235497ac1e07f0a99e9f40e47f6e0f6783fe30500df08fc42/pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6", size = 1776715 }, + { url = "https://files.pythonhosted.org/packages/18/50/5a4e9120b395108c2a0441a425356c0d26a655d7c617288bec1c28b854ac/pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a", size = 1789023 }, + { url = "https://files.pythonhosted.org/packages/c7/e5/f19e13ba86b968d024b56aa53f40b24828652ac026e5addd0ae49eeada02/pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3", size = 1775598 }, + { url = "https://files.pythonhosted.org/packages/c9/c7/f3c29bed28bd022c783baba5bf9946c4f694cb837a687e62f453c81eb5c6/pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1", size = 1977691 }, + { url = "https://files.pythonhosted.org/packages/41/3e/f62c2a05c554fff34570f6788617e9670c83ed7bc07d62a55cccd1bc0be6/pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953", size = 2693214 }, + { url = "https://files.pythonhosted.org/packages/ae/49/8a6fe79d35e2f3bea566d8ea0e4e6f436d4f749d7838c8e8c4c5148ae706/pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98", size = 2061047 }, + { url = "https://files.pythonhosted.org/packages/51/c6/585355c7c8561e11197dbf6333c57dd32f9f62165d48589b57ced2373d97/pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a", size = 1895106 }, + { url = "https://files.pythonhosted.org/packages/ce/23/829f6b87de0775919e82f8addef8b487ace1c77bb4cb754b217f7b1301b6/pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a", size = 1968506 }, + { url = "https://files.pythonhosted.org/packages/ca/2f/f8ca8f0c40b3ee0a4d8730a51851adb14c5eda986ec09f8d754b2fba784e/pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840", size = 2110217 }, + { url = "https://files.pythonhosted.org/packages/bb/a0/1876656c7b17eb69cc683452cce6bb890dd722222a71b3de57ddb512f561/pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250", size = 1709669 }, + { url = "https://files.pythonhosted.org/packages/be/4a/576524eefa9b301c088c4818dc50ff1c51a88fe29efd87ab75748ae15fd7/pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c", size = 1902386 }, + { url = "https://files.pythonhosted.org/packages/61/db/f6a724db226d990a329910727cfac43539ff6969edc217286dd05cda3ef6/pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312", size = 1834507 }, + { url = "https://files.pythonhosted.org/packages/9b/83/6f2bfe75209d557ae1c3550c1252684fc1827b8b12fbed84c3b4439e135d/pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88", size = 1773527 }, + { url = "https://files.pythonhosted.org/packages/93/ef/513ea76d7ca81f2354bb9c8d7839fc1157673e652613f7e1aff17d8ce05d/pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc", size = 1787879 }, + { url = "https://files.pythonhosted.org/packages/31/0a/ac294caecf235f0cc651de6232f1642bb793af448d1cfc541b0dc1fd72b8/pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43", size = 1774694 }, + { url = "https://files.pythonhosted.org/packages/46/a4/08f12b5512f095963550a7cb49ae010e3f8f3f22b45e508c2cb4d7744fce/pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6", size = 1976369 }, + { url = "https://files.pythonhosted.org/packages/15/59/b2495be4410462aedb399071c71884042a2c6443319cbf62d00b4a7ed7a5/pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121", size = 2691250 }, + { url = "https://files.pythonhosted.org/packages/3c/ae/fc99ce1ba791c9e9d1dee04ce80eef1dae5b25b27e3fc8e19f4e3f1348bf/pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1", size = 2061462 }, + { url = "https://files.pythonhosted.org/packages/44/bb/eb07cbe47cfd638603ce3cb8c220f1a054b821e666509e535f27ba07ca5f/pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b", size = 1893923 }, + { url = "https://files.pythonhosted.org/packages/ce/ef/5a52400553b8faa0e7f11fd7a2ba11e8d2feb50b540f9e7973c49b97eac0/pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27", size = 1966779 }, + { url = "https://files.pythonhosted.org/packages/4c/5b/fb37fe341344d9651f5c5f579639cd97d50a457dc53901aa8f7e9f28beb9/pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b", size = 2109044 }, + { url = "https://files.pythonhosted.org/packages/70/1a/6f7278802dbc66716661618807ab0dfa4fc32b09d1235923bbbe8b3a5757/pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a", size = 1708265 }, + { url = "https://files.pythonhosted.org/packages/35/7f/58758c42c61b0bdd585158586fecea295523d49933cb33664ea888162daf/pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2", size = 1901750 }, + { url = "https://files.pythonhosted.org/packages/6f/47/ef0d60ae23c41aced42921728650460dc831a0adf604bfa66b76028cb4d0/pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231", size = 1839225 }, + { url = "https://files.pythonhosted.org/packages/6a/23/430f2878c9cd977a61bb39f71751d9310ec55cee36b3d5bf1752c6341fd0/pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9", size = 1768604 }, + { url = "https://files.pythonhosted.org/packages/9e/2b/ec4e7225dee79e0dc80ccc3c35ab33cc2c4bbb8a1a7ecf060e5e453651ec/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f", size = 1789767 }, + { url = "https://files.pythonhosted.org/packages/64/b0/38b24a1fa6d2f96af3148362e10737ec073768cd44d3ec21dca3be40a519/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52", size = 1772061 }, + { url = "https://files.pythonhosted.org/packages/5e/da/bb73274c42cb60decfa61e9eb0c9029da78b3b9af0a9de0309dbc8ff87b6/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237", size = 1974573 }, + { url = "https://files.pythonhosted.org/packages/c8/65/41693110fb3552556180460daffdb8bbeefb87fc026fd9aa4b849374015c/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe", size = 2625596 }, + { url = "https://files.pythonhosted.org/packages/09/b3/a5a54b47cccd1ab661ed5775235c5e06924753c2d4817737c5667bfa19a8/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e", size = 2099064 }, + { url = "https://files.pythonhosted.org/packages/52/fa/443a7a6ea54beaba45ff3a59f3d3e6e3004b7460bcfb0be77bcf98719d3b/pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24", size = 1900345 }, + { url = "https://files.pythonhosted.org/packages/8e/e6/9aca9ffae60f9cdf0183069de3e271889b628d0fb175913fcb3db5618fb1/pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1", size = 1968252 }, + { url = "https://files.pythonhosted.org/packages/46/5e/6c716810ea20a6419188992973a73c2fb4eb99cd382368d0637ddb6d3c99/pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd", size = 2119191 }, + { url = "https://files.pythonhosted.org/packages/06/fc/6123b00a9240fbb9ae0babad7a005d51103d9a5d39c957a986f5cdd0c271/pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688", size = 1717788 }, + { url = "https://files.pythonhosted.org/packages/d5/36/e61ad5a46607a469e2786f398cd671ebafcd9fb17f09a2359985c7228df5/pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d", size = 1898188 }, + { url = "https://files.pythonhosted.org/packages/49/75/40b0e98b658fdba02a693b3bacb4c875a28bba87796c7b13975976597d8c/pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686", size = 1838688 }, + { url = "https://files.pythonhosted.org/packages/75/02/d8ba2d4a266591a6a623c68b331b96523d4b62ab82a951794e3ed8907390/pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a", size = 1768409 }, + { url = "https://files.pythonhosted.org/packages/91/ae/25ecd9bc4ce4993e99a1a3c9ab111c082630c914260e129572fafed4ecc2/pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b", size = 1789317 }, + { url = "https://files.pythonhosted.org/packages/7a/80/72057580681cdbe55699c367963d9c661b569a1d39338b4f6239faf36cdc/pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19", size = 1771949 }, + { url = "https://files.pythonhosted.org/packages/a2/be/d9bbabc55b05019013180f141fcaf3b14dbe15ca7da550e95b60c321009a/pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac", size = 1974392 }, + { url = "https://files.pythonhosted.org/packages/79/2d/7bcd938c6afb0f40293283f5f09988b61fb0a4f1d180abe7c23a2f665f8e/pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703", size = 2625565 }, + { url = "https://files.pythonhosted.org/packages/ac/88/ca758e979457096008a4b16a064509028e3e092a1e85a5ed6c18ced8da88/pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c", size = 2098784 }, + { url = "https://files.pythonhosted.org/packages/eb/de/2fad6d63c3c42e472e985acb12ec45b7f56e42e6f4cd6dfbc5e87ee8678c/pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83", size = 1900198 }, + { url = "https://files.pythonhosted.org/packages/fe/50/077c7f35b6488dc369a6d22993af3a37901e198630f38ac43391ca730f5b/pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203", size = 1968005 }, + { url = "https://files.pythonhosted.org/packages/5d/1f/f378631574ead46d636b9a04a80ff878b9365d4b361b1905ef1667d4182a/pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0", size = 2118920 }, + { url = "https://files.pythonhosted.org/packages/7a/ea/e4943f17df7a3031d709481fe4363d4624ae875a6409aec34c28c9e6cf59/pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e", size = 1717397 }, + { url = "https://files.pythonhosted.org/packages/13/63/b95781763e8d84207025071c0cec16d921c0163c7a9033ae4b9a0e020dc7/pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20", size = 1898013 }, + { url = "https://files.pythonhosted.org/packages/73/73/0c7265903f66cce39ed7ca939684fba344210cefc91ccc999cfd5b113fd3/pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906", size = 1828190 }, + { url = "https://files.pythonhosted.org/packages/27/55/60b8b0e58b49ee3ed36a18562dd7c6bc06a551c390e387af5872a238f2ec/pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94", size = 1715252 }, + { url = "https://files.pythonhosted.org/packages/28/3d/d66314bad6bb777a36559195a007b31e916bd9e2c198f7bb8f4ccdceb4fa/pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f", size = 1782641 }, + { url = "https://files.pythonhosted.org/packages/9e/f5/f178f4354d0d6c1431a8f9ede71f3c4269ac4dc55d314fdb7555814276dc/pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482", size = 1928788 }, + { url = "https://files.pythonhosted.org/packages/9c/51/1f5e27bb194df79e30b593b608c66e881ed481241e2b9ed5bdf86d165480/pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6", size = 1886116 }, + { url = "https://files.pythonhosted.org/packages/ac/76/450d9258c58dc7c70b9e3aadf6bebe23ddd99e459c365e2adbde80e238da/pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc", size = 1960125 }, + { url = "https://files.pythonhosted.org/packages/dd/9e/0309a7a4bea51771729515e413b3987be0789837de99087f7415e0db1f9b/pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99", size = 2100407 }, + { url = "https://files.pythonhosted.org/packages/af/93/06d44e08277b3b818b75bd5f25e879d7693e4b7dd3505fde89916fcc9ca2/pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6", size = 1914966 }, +] + +[[package]] +name = "pydocstyle" +version = "6.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "snowballstemmer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/d5385ca59fd065e3c6a5fe19f9bc9d5ea7f2509fa8c9c22fb6b2031dd953/pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1", size = 36796 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/ea/99ddefac41971acad68f14114f38261c1f27dac0b3ec529824ebc739bdaa/pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", size = 38038 }, +] + +[[package]] +name = "pyflakes" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/fb/7251eaec19a055ec6aafb3d1395db7622348130d1b9b763f78567b2aab32/pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc", size = 63636 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/e9/1e1fd7fae559bfd07704991e9a59dd1349b72423c904256c073ce88a9940/pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774", size = 62616 }, +] + +[[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 = "pyjwt" +version = "2.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/68/ce067f09fca4abeca8771fe667d89cc347d1e99da3e093112ac329c6020e/pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c", size = 78825 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/84/0fdf9b18ba31d69877bd39c9cd6052b47f3761e9910c15de788e519f079f/PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", size = 22344 }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/d3/fb86beeaa4416f73a28a5e8d440976b7cada2b2d7b5e715b2bd849d4de32/pymdown_extensions-10.9.tar.gz", hash = "sha256:6ff740bcd99ec4172a938970d42b96128bdc9d4b9bcad72494f29921dc69b753", size = 812128 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/41/18b5dc5e97ec3ff1c2f51d372e570a9fbe231f1124dcc36dbc6b47f93058/pymdown_extensions-10.9-py3-none-any.whl", hash = "sha256:d323f7e90d83c86113ee78f3fe62fc9dee5f56b54d912660703ea1816fed5626", size = 250954 }, +] + +[[package]] +name = "pyspelling" +version = "2.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "html5lib" }, + { name = "lxml" }, + { name = "markdown" }, + { name = "pyyaml" }, + { name = "soupsieve" }, + { name = "wcmatch" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/12/07/168a857755a29b7e41550a28cd8f527025bc62fcb36a951d8f3f2eedcdf7/pyspelling-2.10.tar.gz", hash = "sha256:acd67133c1b7cecd410e3d4489e61f2e4b1f0b6acf1ae6c48c240fbb21729c37", size = 148239 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/16/242558b5c5cb73efd52490f1e6bfb03eae63b2585770b9cae78bd491ef0b/pyspelling-2.10-py3-none-any.whl", hash = "sha256:9b079dd238bd0616a49f9ac5df32799beb851dddc5ed7634f551e7df1aeee943", size = 45035 }, +] + +[[package]] +name = "pytest" +version = "7.4.4" +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/80/1f/9d8e98e4133ffb16c90f3b405c43e38d3abb715bb5d7a63a5a684f7e46a3/pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280", size = 1357116 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8", size = 325287 }, +] + +[[package]] +name = "pytest-cov" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/15/da3df99fd551507694a9b01f512a2f6cf1254f33601605843c3775f39460/pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6", size = 63245 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/4b/8b78d126e275efa2379b1c2e09dc52cf70df16fc3b90613ef82531499d73/pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a", size = 21949 }, +] + +[[package]] +name = "pytest-html" +version = "4.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "pytest" }, + { name = "pytest-metadata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/ab/4862dcb5a8a514bd87747e06b8d55483c0c9e987e1b66972336946e49b49/pytest_html-4.1.1.tar.gz", hash = "sha256:70a01e8ae5800f4a074b56a4cb1025c8f4f9b038bba5fe31e3c98eb996686f07", size = 150773 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/c7/c160021cbecd956cc1a6f79e5fe155f7868b2e5b848f1320dad0b3e3122f/pytest_html-4.1.1-py3-none-any.whl", hash = "sha256:c8152cea03bd4e9bee6d525573b67bbc6622967b72b9628dda0ea3e2a0b5dd71", size = 23491 }, +] + +[[package]] +name = "pytest-metadata" +version = "3.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/85/8c969f8bec4e559f8f2b958a15229a35495f5b4ce499f6b865eac54b878d/pytest_metadata-3.1.1.tar.gz", hash = "sha256:d2a29b0355fbc03f168aa96d41ff88b1a3b44a3b02acbe491801c98a048017c8", size = 9952 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/43/7e7b2ec865caa92f67b8f0e9231a798d102724ca4c0e1f414316be1c1ef2/pytest_metadata-3.1.1-py3-none-any.whl", hash = "sha256:c8e0844db684ee1c798cfa38908d20d67d0463ecb6137c72e91f418558dd5f4b", size = 11428 }, +] + +[[package]] +name = "pytest-xdist" +version = "3.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/c4/3c310a19bc1f1e9ef50075582652673ef2bfc8cd62afef9585683821902f/pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d", size = 84060 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/82/1d96bf03ee4c0fdc3c0cbe61470070e659ca78dc0086fb88b66c185e2449/pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7", size = 46108 }, +] + +[[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 }, +] + +[[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.7.24" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/51/64256d0dc72816a4fe3779449627c69ec8fee5a5625fd60ba048f53b3478/regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506", size = 393485 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/97/283bd32777e6c30a9bede976cd72ba4b9aa144dc0f0f462bd37fa1a86e01/regex-2024.7.24-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b0d3f567fafa0633aee87f08b9276c7062da9616931382993c03808bb68ce", size = 470812 }, + { url = "https://files.pythonhosted.org/packages/e4/80/80bc4d7329d04ba519ebcaf26ae21d9e30d33934c458691177c623ceff70/regex-2024.7.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3426de3b91d1bc73249042742f45c2148803c111d1175b283270177fdf669024", size = 282129 }, + { url = "https://files.pythonhosted.org/packages/e5/8a/cddcb7942d05ad9a427ad97ab29f1a62c0607ab72bdb2f3a26fc5b07ac0f/regex-2024.7.24-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f273674b445bcb6e4409bf8d1be67bc4b58e8b46fd0d560055d515b8830063cd", size = 278909 }, + { url = "https://files.pythonhosted.org/packages/a6/d4/93b4011cb83f9a66e0fa398b4d3c6d564d94b686dace676c66502b13dae9/regex-2024.7.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23acc72f0f4e1a9e6e9843d6328177ae3074b4182167e34119ec7233dfeccf53", size = 777687 }, + { url = "https://files.pythonhosted.org/packages/d0/11/d0a12e1cecc1d35bbcbeb99e2ddcb8c1b152b1b58e2ff55f50c3d762b09e/regex-2024.7.24-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65fd3d2e228cae024c411c5ccdffae4c315271eee4a8b839291f84f796b34eca", size = 818982 }, + { url = "https://files.pythonhosted.org/packages/ae/41/01a073765d75427e24710af035d8f0a773b5cedf23f61b63e7ef2ce960d6/regex-2024.7.24-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c414cbda77dbf13c3bc88b073a1a9f375c7b0cb5e115e15d4b73ec3a2fbc6f59", size = 804015 }, + { url = "https://files.pythonhosted.org/packages/3e/66/04b63f31580026c8b819aed7f171149177d10cfab27477ea8800a2268d50/regex-2024.7.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7a89eef64b5455835f5ed30254ec19bf41f7541cd94f266ab7cbd463f00c41", size = 776517 }, + { url = "https://files.pythonhosted.org/packages/be/49/0c08a7a232e4e26e17afeedf13f331224d9377dde4876ed6e21e4a584a5d/regex-2024.7.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19c65b00d42804e3fbea9708f0937d157e53429a39b7c61253ff15670ff62cb5", size = 766860 }, + { url = "https://files.pythonhosted.org/packages/24/44/35769388845cdd7be97e1232a59446b738054b61bc9c92a3b0bacfaf7bb1/regex-2024.7.24-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a5486ca56c8869070a966321d5ab416ff0f83f30e0e2da1ab48815c8d165d46", size = 692181 }, + { url = "https://files.pythonhosted.org/packages/50/be/4e09d5bc8de176153f209c95ca4e64b9def1748d693694a95dd4401ee7be/regex-2024.7.24-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f51f9556785e5a203713f5efd9c085b4a45aecd2a42573e2b5041881b588d1f", size = 762956 }, + { url = "https://files.pythonhosted.org/packages/90/63/b37152f25fe348aa31806bafa91df607d096e8f477fed9a5cf3de339dd5f/regex-2024.7.24-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a4997716674d36a82eab3e86f8fa77080a5d8d96a389a61ea1d0e3a94a582cf7", size = 771978 }, + { url = "https://files.pythonhosted.org/packages/ab/ac/38186431f7c1874e3f790669be933accf1090ee53aba0ab1a811ef38f07e/regex-2024.7.24-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c0abb5e4e8ce71a61d9446040c1e86d4e6d23f9097275c5bd49ed978755ff0fe", size = 840800 }, + { url = "https://files.pythonhosted.org/packages/e8/23/91b04dbf51a2c0ddf5b1e055e9e05ed091ebcf46f2b0e6e3d2fff121f903/regex-2024.7.24-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:18300a1d78cf1290fa583cd8b7cde26ecb73e9f5916690cf9d42de569c89b1ce", size = 838991 }, + { url = "https://files.pythonhosted.org/packages/36/fd/822110cc14b99bdd7d8c61487bc774f454120cd3d7492935bf13f3399716/regex-2024.7.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:416c0e4f56308f34cdb18c3f59849479dde5b19febdcd6e6fa4d04b6c31c9faa", size = 767539 }, + { url = "https://files.pythonhosted.org/packages/82/54/e24a8adfca74f9a421cd47657c51413919e7755e729608de6f4c5556e002/regex-2024.7.24-cp310-cp310-win32.whl", hash = "sha256:fb168b5924bef397b5ba13aabd8cf5df7d3d93f10218d7b925e360d436863f66", size = 257712 }, + { url = "https://files.pythonhosted.org/packages/fb/cc/6485c2fc72d0de9b55392246b80921639f1be62bed1e33e982940306b5ba/regex-2024.7.24-cp310-cp310-win_amd64.whl", hash = "sha256:6b9fc7e9cc983e75e2518496ba1afc524227c163e43d706688a6bb9eca41617e", size = 269661 }, + { url = "https://files.pythonhosted.org/packages/cb/ec/261f8434a47685d61e59a4ef3d9ce7902af521219f3ebd2194c7adb171a6/regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281", size = 470810 }, + { url = "https://files.pythonhosted.org/packages/f0/47/f33b1cac88841f95fff862476a9e875d9a10dae6912a675c6f13c128e5d9/regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b", size = 282126 }, + { url = "https://files.pythonhosted.org/packages/fc/1b/256ca4e2d5041c0aa2f1dc222f04412b796346ab9ce2aa5147405a9457b4/regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a", size = 278920 }, + { url = "https://files.pythonhosted.org/packages/91/03/4603ec057c0bafd2f6f50b0bdda4b12a0ff81022decf1de007b485c356a6/regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73", size = 785420 }, + { url = "https://files.pythonhosted.org/packages/75/f8/13b111fab93e6273e26de2926345e5ecf6ddad1e44c4d419d7b0924f9c52/regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2", size = 828164 }, + { url = "https://files.pythonhosted.org/packages/4a/80/bc3b9d31bd47ff578758af929af0ac1d6169b247e26fa6e87764007f3d93/regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e", size = 812621 }, + { url = "https://files.pythonhosted.org/packages/8b/77/92d4a14530900d46dddc57b728eea65d723cc9fcfd07b96c2c141dabba84/regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51", size = 786609 }, + { url = "https://files.pythonhosted.org/packages/35/58/06695fd8afad4c8ed0a53ec5e222156398b9fe5afd58887ab94ea68e4d16/regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364", size = 775290 }, + { url = "https://files.pythonhosted.org/packages/1b/0f/50b97ee1fc6965744b9e943b5c0f3740792ab54792df73d984510964ef29/regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee", size = 772849 }, + { url = "https://files.pythonhosted.org/packages/8f/64/565ff6cf241586ab7ae76bb4138c4d29bc1d1780973b457c2db30b21809a/regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c", size = 778428 }, + { url = "https://files.pythonhosted.org/packages/e5/fe/4ceabf4382e44e1e096ac46fd5e3bca490738b24157116a48270fd542e88/regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce", size = 849436 }, + { url = "https://files.pythonhosted.org/packages/68/23/1868e40d6b594843fd1a3498ffe75d58674edfc90d95e18dd87865b93bf2/regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1", size = 849484 }, + { url = "https://files.pythonhosted.org/packages/f3/52/bff76de2f6e2bc05edce3abeb7e98e6309aa022fc06071100a0216fbeb50/regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e", size = 776712 }, + { url = "https://files.pythonhosted.org/packages/f2/72/70ade7b0b5fe5c6df38fdfa2a5a8273e3ea6a10b772aa671b7e889e78bae/regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c", size = 257716 }, + { url = "https://files.pythonhosted.org/packages/04/4d/80e04f4e27ab0cbc9096e2d10696da6d9c26a39b60db52670fd57614fea5/regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52", size = 269662 }, + { url = "https://files.pythonhosted.org/packages/0f/26/f505782f386ac0399a9237571833f187414882ab6902e2e71a1ecb506835/regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86", size = 471748 }, + { url = "https://files.pythonhosted.org/packages/bb/1d/ea9a21beeb433dbfca31ab82867d69cb67ff8674af9fab6ebd55fa9d3387/regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad", size = 282841 }, + { url = "https://files.pythonhosted.org/packages/9b/f2/c6182095baf0a10169c34e87133a8e73b2e816a80035669b1278e927685e/regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9", size = 279114 }, + { url = "https://files.pythonhosted.org/packages/72/58/b5161bf890b6ca575a25685f19a4a3e3b6f4a072238814f8658123177d84/regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289", size = 789749 }, + { url = "https://files.pythonhosted.org/packages/09/fb/5381b19b62f3a3494266be462f6a015a869cf4bfd8e14d6e7db67e2c8069/regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9", size = 831666 }, + { url = "https://files.pythonhosted.org/packages/3d/6d/2a21c85f970f9be79357d12cf4b97f4fc6bf3bf6b843c39dabbc4e5f1181/regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c", size = 817544 }, + { url = "https://files.pythonhosted.org/packages/f9/ae/5f23e64f6cf170614237c654f3501a912dfb8549143d4b91d1cd13dba319/regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440", size = 790854 }, + { url = "https://files.pythonhosted.org/packages/29/0a/d04baad1bbc49cdfb4aef90c4fc875a60aaf96d35a1616f1dfe8149716bc/regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610", size = 779242 }, + { url = "https://files.pythonhosted.org/packages/3a/27/b242a962f650c3213da4596d70e24c7c1c46e3aa0f79f2a81164291085f8/regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5", size = 776932 }, + { url = "https://files.pythonhosted.org/packages/9c/ae/de659bdfff80ad2c0b577a43dd89dbc43870a4fc4bbf604e452196758e83/regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799", size = 784521 }, + { url = "https://files.pythonhosted.org/packages/d4/ac/eb6a796da0bdefbf09644a7868309423b18d344cf49963a9d36c13502d46/regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05", size = 854548 }, + { url = "https://files.pythonhosted.org/packages/56/77/fde8d825dec69e70256e0925af6c81eea9acf0a634d3d80f619d8dcd6888/regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94", size = 853345 }, + { url = "https://files.pythonhosted.org/packages/ff/04/2b79ad0bb9bc05ab4386caa2c19aa047a66afcbdfc2640618ffc729841e4/regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38", size = 781414 }, + { url = "https://files.pythonhosted.org/packages/bf/71/d0af58199283ada7d25b20e416f5b155f50aad99b0e791c0966ff5a1cd00/regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc", size = 258125 }, + { url = "https://files.pythonhosted.org/packages/95/b3/10e875c45c60b010b66fc109b899c6fc4f05d485fe1d54abff98ce791124/regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908", size = 269162 }, +] + +[[package]] +name = "remerkleable" +version = "0.1.28" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/a3/5b1206c4281f7337945a8e86ef73f40093c41f3b78291d6f66250fe5aaf8/remerkleable-0.1.28.tar.gz", hash = "sha256:1e19e9a927961b29c4efa210795bfad5d20a28545a6f78f7552b1e4449c24890", size = 45671 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/c2/c89771e64163950a0016251080523cfbdf1f1d2cae2ad0b8b9c52bc0c846/remerkleable-0.1.28-py3-none-any.whl", hash = "sha256:133cb1283f1d6fd2a020f47ee3653e93385acf2aa4ddc30f3d00eb9404751bda", size = 51439 }, +] + +[[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 = "rich" +version = "13.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cf/60/5959113cae0ce512cf246a6871c623117330105a0d5f59b4e26138f2c9cc/rich-13.8.0.tar.gz", hash = "sha256:a5ac1f1cd448ade0d59cc3356f7db7a7ccda2c8cbae9c7a90c28ff463d3e91f4", size = 222072 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/d9/c2a126eeae791e90ea099d05cb0515feea3688474b978343f3cdcfe04523/rich-13.8.0-py3-none-any.whl", hash = "sha256:2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc", size = 241597 }, +] + +[[package]] +name = "rlp" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "eth-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/63/8b5205a7f9e2792137676c2d29bd6bc9cbecca95015a55ed54d6dd02f3f6/rlp-3.0.0.tar.gz", hash = "sha256:63b0465d2948cd9f01de449d7adfb92d207c1aef3982f20310f8009be4a507e8", size = 40017 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/24/03e9b6f0c61e92ed27b1e16a5393034ae07b98c307e3b0e6be3e03183ba8/rlp-3.0.0-py2.py3-none-any.whl", hash = "sha256:d2a963225b3f26795c5b52310e0871df9824af56823d739511583ef459895a7d", size = 20154 }, +] + +[[package]] +name = "ruamel-yaml" +version = "0.17.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ruamel-yaml-clib", marker = "python_full_version < '3.11' and platform_python_implementation == 'CPython'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/a9/6ed24832095b692a8cecc323230ce2ec3480015fbfa4b79941bd41b23a3c/ruamel.yaml-0.17.21.tar.gz", hash = "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af", size = 128123 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/cb/938214ac358fbef7058343b3765c79a1b7ed0c366f7f992ce7ff38335652/ruamel.yaml-0.17.21-py3-none-any.whl", hash = "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7", size = 109478 }, +] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/ab/bab9eb1566cd16f060b54055dd39cf6a34bfa0240c53a7218c43e974295b/ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512", size = 213824 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/01/37ac131614f71b98e9b148b2d7790662dcee92217d2fb4bac1aa377def33/ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d", size = 148236 }, + { url = "https://files.pythonhosted.org/packages/61/ee/4874c9fc96010fce85abefdcbe770650c5324288e988d7a48b527a423815/ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462", size = 133996 }, + { url = "https://files.pythonhosted.org/packages/d3/62/c60b034d9a008bbd566eeecf53a5a4c73d191c8de261290db6761802b72d/ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412", size = 526680 }, + { url = "https://files.pythonhosted.org/packages/90/8c/6cdb44f548b29eb6328b9e7e175696336bc856de2ff82e5776f860f03822/ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f", size = 605853 }, + { url = "https://files.pythonhosted.org/packages/88/30/fc45b45d5eaf2ff36cffd215a2f85e9b90ac04e70b97fd4097017abfb567/ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334", size = 655206 }, + { url = "https://files.pythonhosted.org/packages/af/dc/133547f90f744a0c827bac5411d84d4e81da640deb3af1459e38c5f3b6a0/ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d", size = 689649 }, + { url = "https://files.pythonhosted.org/packages/23/1d/589139191b187a3c750ae8d983c42fd799246d5f0dd84451a0575c9bdbe9/ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d", size = 100044 }, + { url = "https://files.pythonhosted.org/packages/4f/5b/744df20285a75ac4c606452ce9a0fcc42087d122f42294518ded1017697c/ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31", size = 117825 }, + { url = "https://files.pythonhosted.org/packages/b1/15/971b385c098e8d0d170893f5ba558452bb7b776a0c90658b8f4dd0e3382b/ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069", size = 148870 }, + { url = "https://files.pythonhosted.org/packages/01/b0/4ddef56e9f703d7909febc3a421d709a3482cda25826816ec595b73e3847/ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248", size = 134475 }, + { url = "https://files.pythonhosted.org/packages/a4/f7/22d6b620ed895a05d40802d8281eff924dc6190f682d933d4efff60db3b5/ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b", size = 544020 }, + { url = "https://files.pythonhosted.org/packages/7c/e4/0d19d65e340f93df1c47f323d95fa4b256bb28320290f5fddef90837853a/ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe", size = 642643 }, + { url = "https://files.pythonhosted.org/packages/c9/ff/f781eb5e2ae011e586d5426e2086a011cf1e0f59704a6cad1387975c5a62/ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899", size = 695832 }, + { url = "https://files.pythonhosted.org/packages/e3/41/f62e67ac651358b8f0d60cfb12ab2daf99b1b69eeaa188d0cec809d943a6/ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9", size = 730923 }, + { url = "https://files.pythonhosted.org/packages/9f/f0/19ab8acbf983cd1b37f47d27ceb8b10a738d60d36316a54bad57e0d73fbb/ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7", size = 99999 }, + { url = "https://files.pythonhosted.org/packages/ec/54/d8a795997921d87224c65d44499ca595a833093fb215b133f920c1062956/ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb", size = 118008 }, + { url = "https://files.pythonhosted.org/packages/7a/a2/eb5e9d088cb9d15c24d956944c09dca0a89108ad6e2e913c099ef36e3f0d/ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1", size = 144636 }, + { url = "https://files.pythonhosted.org/packages/66/98/8de4f22bbfd9135deb3422e96d450c4bc0a57d38c25976119307d2efe0aa/ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2", size = 135684 }, + { url = "https://files.pythonhosted.org/packages/30/d3/5fe978cd01a61c12efd24d65fa68c6f28f28c8073a06cf11db3a854390ca/ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92", size = 734571 }, + { url = "https://files.pythonhosted.org/packages/55/b3/e2531a050758b717c969cbf76c103b75d8a01e11af931b94ba656117fbe9/ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62", size = 643946 }, + { url = "https://files.pythonhosted.org/packages/0d/aa/06db7ca0995b513538402e11280282c615b5ae5f09eb820460d35fb69715/ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9", size = 692169 }, + { url = "https://files.pythonhosted.org/packages/27/38/4cf4d482b84ecdf51efae6635cc5483a83cf5ca9d9c13e205a750e251696/ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d", size = 740325 }, + { url = "https://files.pythonhosted.org/packages/6f/67/c62c6eea53a4feb042727a3d6c18f50dc99683c2b199c06bd2a9e3db8e22/ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa", size = 98639 }, + { url = "https://files.pythonhosted.org/packages/10/d2/52a3d810d0b5b3720725c0504a27b3fced7b6f310fe928f7019d79387bc1/ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b", size = 115305 }, +] + +[[package]] +name = "semver" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/6c/a536cc008f38fd83b3c1b98ce19ead13b746b5588c9a0cb9dd9f6ea434bc/semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc", size = 214988 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/77/0cc7a8a3bc7e53d07e8f47f147b92b0960e902b8254859f4aee5c4d7866b/semver-3.0.2-py3-none-any.whl", hash = "sha256:b1ea4686fe70b981f85359eda33199d60c53964284e0cfb4977d243e37cf4bf4", size = 17099 }, +] + +[[package]] +name = "setuptools" +version = "74.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/21/8fd457d5a979109603e0e460c73177c3a9b6b7abcd136d0146156da95895/setuptools-74.0.0.tar.gz", hash = "sha256:a85e96b8be2b906f3e3e789adec6a9323abf79758ecfa3065bd740d81158b11e", size = 1389536 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b5/168cec9a10bf93b60b8f9af7f4e61d526e31e1aad8b9be0e30837746d700/setuptools-74.0.0-py3-none-any.whl", hash = "sha256:0274581a0037b638b9fc1c6883cc71c0210865aaa76073f7882376b641b84e8f", size = 1301729 }, +] + +[[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 = "smmap" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/88/04/b5bf6d21dc4041000ccba7eb17dd3055feb237e7ffc2c20d3fae3af62baa/smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62", size = 22291 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/a5/10f97f73544edcdef54409f1d839f6049a0d79df68adbc1ceb24d1aaca42/smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da", size = 24282 }, +] + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, +] + +[[package]] +name = "solc-select" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pycryptodome" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/a0/2a2bfbbab1d9bd4e1a24e3604c30b5d6f84219238f3c98f06191faf5d019/solc-select-1.0.4.tar.gz", hash = "sha256:db7b9de009af6de3a5416b80bbe5b6d636bf314703c016319b8c1231e248a6c7", size = 21307 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/a6/e2b2529f77431bd610de0a09d633768e9538f986fa606180b3b9a4a05a89/solc_select-1.0.4-py3-none-any.whl", hash = "sha256:9a28b8a612ff18a171929d23e2ed68a6263f4e11784fc47fa81476a3219874cb", size = 20710 }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, +] + +[[package]] +name = "soupsieve" +version = "2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 }, +] + +[[package]] +name = "tenacity" +version = "8.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/4d/6a19536c50b849338fcbe9290d562b52cbdcf30d8963d3588a68a4107df1/tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", size = 47309 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165 }, +] + +[[package]] +name = "tinycss2" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/44/6f/38d2335a2b70b9982d112bb177e3dbe169746423e33f718bf5e9c7b3ddd3/tinycss2-1.3.0.tar.gz", hash = "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d", size = 67360 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/4d/0db5b8a613d2a59bbc29bc5bb44a2f8070eb9ceab11c50d477502a8a0092/tinycss2-1.3.0-py3-none-any.whl", hash = "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7", size = 22532 }, +] + +[[package]] +name = "tomli" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/3f/d7af728f075fb08564c5949a9c95e44352e23dee646869fa104a3b2060a3/tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f", size = 15164 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", size = 12757 }, +] + +[[package]] +name = "toolz" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3e/bf/5e12db234df984f6df3c7f12f1428aa680ba4e101f63f4b8b3f9e8d2e617/toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d", size = 66550 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/8a/d82202c9f89eab30f9fc05380daae87d617e2ad11571ab23d7c13a29bb54/toolz-0.12.1-py3-none-any.whl", hash = "sha256:d22731364c07d72eea0a0ad45bafb2c2937ab6fd38a3507bf55eae8744aa7d85", size = 56121 }, +] + +[[package]] +name = "trie" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "eth-hash" }, + { name = "eth-utils" }, + { name = "hexbytes" }, + { name = "rlp" }, + { name = "sortedcontainers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/3c/8a90615f39890c503d569f6973e983973a68d07ffa90190757210a95fecc/trie-2.0.2.tar.gz", hash = "sha256:8bfc6b82979b7caa6f020a89c9142c7522f017788240487d1c941b0ad82e7132", size = 39304 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/a6/2f2ee141c4fbf517a823aa17446a4368d030e3ce629568d08e7c01da6210/trie-2.0.2-py3-none-any.whl", hash = "sha256:edef6b392f49f80be31c167236c6569aa07d7926138d5fe23d327d65d62b7201", size = 38583 }, +] + +[[package]] +name = "types-requests" +version = "2.32.0.20240712" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/9e/7663eb27c33568b8fc20ccdaf2a1ce53a9530c42a7cceb9f552a6ff4a1d8/types-requests-2.32.0.20240712.tar.gz", hash = "sha256:90c079ff05e549f6bf50e02e910210b98b8ff1ebdd18e19c873cd237737c1358", size = 17896 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/4d/cbed87a6912fbd9259ce23a5d4aa1de9816edf75eec6ed9a757c00906c8e/types_requests-2.32.0.20240712-py3-none-any.whl", hash = "sha256:f754283e152c752e46e70942fa2a146b5bc70393522257bb85bd1ef7e019dcc3", size = 15816 }, +] + +[[package]] +name = "types-setuptools" +version = "73.0.0.20240822" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/a8/5b26af1117daf328f3420fce5ad36f9331a2bbc689862923789402eb83d6/types-setuptools-73.0.0.20240822.tar.gz", hash = "sha256:3a060681098eb3fbc2fea0a86f7f6af6aa1ca71906039d88d891ea2cecdd4dbf", size = 42177 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/76/ec2cf632452154ecceaed2075707ca09719238e8ba53b3027f47ba78b90c/types_setuptools-73.0.0.20240822-py3-none-any.whl", hash = "sha256:b9eba9b68546031317a0fa506d4973641d987d74f79e7dd8369ad4f7a93dea17", size = 67135 }, +] + +[[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.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/6d/fa469ae21497ddc8bc93e5877702dca7cb8f911e337aca7452b5724f1bb6/urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168", size = 292266 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/1c/89ffc63a9605b583d5df2be791a27bc1a42b7c32bab68d3c8f2f73a98cd4/urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", size = 121444 }, +] + +[[package]] +name = "verspec" +version = "0.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/44/8126f9f0c44319b2efc65feaad589cadef4d77ece200ae3c9133d58464d0/verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e", size = 27123 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31", size = 19640 }, +] + +[[package]] +name = "watchdog" +version = "5.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/b5/9943b585553bbda2a2795fb0db1d26267e8728f64cb15205dc640a5ecde0/watchdog-5.0.0.tar.gz", hash = "sha256:990aedb9e2f336b45a70aed9c014450e7c4a70fd99c5f5b1834d57e1453a177e", size = 127192 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/c2/9addcac649bc57d1b4d5af0d67109b1d41728f06e2d8ed207cda0f2f4ef2/watchdog-5.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bf3216ec994eabb2212df9861f19056ca0d4cd3516d56cb95801933876519bfe", size = 96112 }, + { url = "https://files.pythonhosted.org/packages/b3/f3/c8daf10cf15d83cb0f35ac2494a95ed419eeceb08fcdffca2681bd720420/watchdog-5.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb59ad83a1700304fc1ac7bc53ae9e5cbe9d60a52ed9bba8e2e2d782a201bb2b", size = 88112 }, + { url = "https://files.pythonhosted.org/packages/40/80/58a2a3fa64048279f250ea1058482da01c5611f90f82ea8f9f8e2295cfee/watchdog-5.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1228cb097e855d1798b550be8f0e9f0cfbac4384f9a3e91f66d250d03e11294e", size = 88742 }, + { url = "https://files.pythonhosted.org/packages/a7/9e/116fe5428214ba8e1139a083e819e8b1231d73d7b600aba9cc7df5338eaa/watchdog-5.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3c177085c3d210d1c73cb4569442bdaef706ebebc423bd7aed9e90fc12b2e553", size = 96112 }, + { url = "https://files.pythonhosted.org/packages/75/94/f43c15bf03de8ce9f29cb82422c0f35f05a4770afbc7f36ca9d55e8d7023/watchdog-5.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01ab36cddc836a0f202c66267daaef92ba5c17c7d6436deff0587bb61234c5c9", size = 88118 }, + { url = "https://files.pythonhosted.org/packages/f3/fd/0f1b0c75db0057475956a68e6896808bfaa6a494e02b88c786da9a86a461/watchdog-5.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0834c21efa3e767849b09e667274604c7cdfe30b49eb95d794565c53f4db3c1e", size = 88745 }, + { url = "https://files.pythonhosted.org/packages/b7/a6/78a205c13e72c3262dc6b5c7deab86a77b2a24dc4e376cd686d383883b7d/watchdog-5.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1e26f570dd7f5178656affb24d6f0e22ce66c8daf88d4061a27bfb9ac866b40d", size = 96207 }, + { url = "https://files.pythonhosted.org/packages/1d/54/c7bff808050273fc7d1fbe2fa649931c90e558816187d6c28086bd31c5ae/watchdog-5.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d146331e6b206baa9f6dd40f72b5783ad2302c240df68e7fce196d30588ccf7b", size = 88161 }, + { url = "https://files.pythonhosted.org/packages/8b/23/92382a9cbd3d9fbc35fa3693eb2932d54d8085af0a10a0af8c1959681c98/watchdog-5.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c96b1706430839872a3e33b9370ee3f7a0079f6b828129d88498ad1f96a0f45", size = 88777 }, + { url = "https://files.pythonhosted.org/packages/96/06/eadb771e73854c2a1fdbd795aefdb6dcdf0aa9e922f98a7e8e72f4f79469/watchdog-5.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:663b096368ed7831ac42259919fdb9e0a1f0a8994d972675dfbcca0225e74de1", size = 96200 }, + { url = "https://files.pythonhosted.org/packages/fc/c5/8356ef0f6b991087aaa0abd303f7f8325bab448a7b3a9cd4a1963a18f124/watchdog-5.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:685931412978d00a91a193d9018fc9e394e565e8e7a0c275512a80e59c6e85f8", size = 88174 }, + { url = "https://files.pythonhosted.org/packages/76/98/25eb610688e465514846eb7fd051b48aac648ec345ad6bd6460a1b0d884a/watchdog-5.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:109daafc5b0f2a98d1fa9475ff9737eb3559d57b18129a36495e20c71de0b44f", size = 88776 }, + { url = "https://files.pythonhosted.org/packages/d5/17/fc54320492875082d7beee4e332112d83e6b5e6ae849fec82314f13f0ecd/watchdog-5.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bc16d448a74a929b896ed9578c25756b2125400b19b3258be8d9a681c7ae8e71", size = 87630 }, + { url = "https://files.pythonhosted.org/packages/42/78/9d0b5df46d54e5c43a8859edb1b2af9410a08d691150181431e52d46c07a/watchdog-5.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7e6b0e9b8a9dc3865d65888b5f5222da4ba9c4e09eab13cff5e305e7b7e7248f", size = 88107 }, + { url = "https://files.pythonhosted.org/packages/48/8a/1e1e36a02a25d0242d0c57fbabcee2296532fe7d0d4e84f7b02fade7872b/watchdog-5.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d76efab5248aafbf8a2c2a63cd7b9545e6b346ad1397af8b862a3bb3140787d8", size = 78803 }, + { url = "https://files.pythonhosted.org/packages/44/25/238a16222369595f144a58d9d5ea3de2f76a0b4c8f4bab80e806174f6a0e/watchdog-5.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:ff4e957c45c446de34c513eadce01d0b65da7eee47c01dce472dd136124552c9", size = 78800 }, + { url = "https://files.pythonhosted.org/packages/4c/28/474243e7b4794c1a3fb7eb8c8b15f486ffdfbc9711055540522a09476975/watchdog-5.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:16c1aa3377bb1f82c5e24277fcbf4e2cac3c4ce46aaaf7212d53caa9076eb7b7", size = 78798 }, + { url = "https://files.pythonhosted.org/packages/36/c0/7dec9f91e684851a5f14edec1bebfe9bed6e6b45bad21396456543c4ba7f/watchdog-5.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:22fcad6168fc43cf0e709bd854be5b8edbb0b260f0a6f28f1ea9baa53c6907f7", size = 78800 }, + { url = "https://files.pythonhosted.org/packages/7b/a9/a0ae3c4e8581741a58a6652bebee255328b786d993db38b8d66660b2b830/watchdog-5.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:0120b2fa65732797ffa65fa8ee5540c288aa861d91447df298626d6385a24658", size = 78802 }, + { url = "https://files.pythonhosted.org/packages/d7/86/51fd182579692c41c1813d9269d349843adeb700adaf6a18d9da0681bcfb/watchdog-5.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2aa59fab7ff75281778c649557275ca3085eccbdf825a0e2a5ca3810e977afe5", size = 78801 }, + { url = "https://files.pythonhosted.org/packages/70/76/062a1e150a2ecbeee87bc1c794e95889eb7122c847666cb3351201386105/watchdog-5.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:78db0fe0336958fc0e1269545c980b6f33d04d184ba191b2800a8b71d3e971a9", size = 78801 }, + { url = "https://files.pythonhosted.org/packages/dd/80/8e4360dcd907e7fb0c718811abecbf11ecf75f2fe92c77a6cfc6ff63158c/watchdog-5.0.0-py3-none-win32.whl", hash = "sha256:d1acef802916083f2ad7988efc7decf07e46e266916c0a09d8fb9d387288ea12", size = 78790 }, + { url = "https://files.pythonhosted.org/packages/bd/94/1344f73df316dd199b50258d2afad05e1843ff87a2dde969640b3bf6c795/watchdog-5.0.0-py3-none-win_amd64.whl", hash = "sha256:3c2d50fdb86aa6df3973313272f5a17eb26eab29ff5a0bf54b6d34597b4dc4e4", size = 78793 }, + { url = "https://files.pythonhosted.org/packages/80/05/4128ae5cdf270bdd80ece30d02c72c0a67433e04c44a3a62e91dce7cfaf6/watchdog-5.0.0-py3-none-win_ia64.whl", hash = "sha256:1d17ec7e022c34fa7ddc72aa41bf28c9d1207ffb193df18ba4f6fde453725b3c", size = 78791 }, +] + +[[package]] +name = "wcmatch" +version = "9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bracex" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/90/a29d5b359c128c48e32a2dc161464d6aab822df82d3bf1c1286231eda3c2/wcmatch-9.0.tar.gz", hash = "sha256:567d66b11ad74384954c8af86f607857c3bdf93682349ad32066231abd556c92", size = 113625 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/da/0633223f30f5db6e52236567e09c28e37ff455b3dfbe0843029206e609e6/wcmatch-9.0-py3-none-any.whl", hash = "sha256:af25922e2b6dbd1550fa37a4c8de7dd558d6c1bb330c641de9b907b9776cb3c4", size = 39139 }, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, +] From 7c3087830aa6ea6d2aaf93498746c9f6cc8d5d54 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Tue, 3 Sep 2024 15:29:33 +0200 Subject: [PATCH 17/17] chore: update uv.lock for updated solc deps (#782) --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index ed7148034c..c755b3b96b 100644 --- a/uv.lock +++ b/uv.lock @@ -640,7 +640,7 @@ requires-dist = [ { name = "rich", specifier = ">=13.7.0,<14" }, { name = "semver", specifier = ">=3.0.1,<4" }, { name = "setuptools" }, - { name = "solc-select", specifier = ">=1.0.4" }, + { name = "solc-select", specifier = ">=1.0.4,<2" }, { name = "tenacity", specifier = ">8.2.0,<9" }, { name = "trie", specifier = ">=2.0.2,<3" }, { name = "types-requests", marker = "extra == 'lint'" },