diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..f0f08f0 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +USER_ADDRESS= +PRIVATE_KEY= diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 902da10..e2c31ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: python-version: [ - "3.8", "3.9", "3.10", "3.11", "3.12", + "3.10", "3.11", "3.12", ] timeout-minutes: 10 steps: @@ -32,6 +32,10 @@ jobs: cache: poetry cache-dependency-path: poetry.lock + - name: Poetry lock + run: | + poetry lock + - name: Install dependencies run: | poetry install diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 704b21f..0710f6a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,10 @@ repos: -- repo: https://github.com/astral-sh/ruff-pre-commit - # Ruff version. - rev: v0.1.4 - hooks: - # Run the linter. - - id: ruff - # Run the formatter. - - id: ruff-format + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.3.7 + hooks: + # Run the linter. + - id: ruff + args: [--fix] + # Run the formatter. + - id: ruff-format diff --git a/Makefile b/Makefile index 0e59d47..21ed7dc 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,27 @@ -.PHONY: codegen +.PHONY: codegen web3_codegen orderbook_codegen subgraph_codegen test lint format remove_unused_imports codegen: web3_codegen orderbook_codegen subgraph_codegen -web3_codegen: - poetry run web3_codegen +# web3_codegen: +# poetry run web3_codegen orderbook_codegen: - datamodel-codegen --url="https://raw.githubusercontent.com/cowprotocol/services/v2.245.1/crates/orderbook/openapi.yml" --output cow_py/order_book/__generated__/model.py --target-python-version 3.12 --output-model-type pydantic_v2.BaseModel --input-file-type openapi + poetry run datamodel-codegen --url="https://raw.githubusercontent.com/cowprotocol/services/v2.245.1/crates/orderbook/openapi.yml" --output cow_py/order_book/generated/model.py --target-python-version 3.12 --output-model-type pydantic_v2.BaseModel --input-file-type openapi subgraph_codegen: - ariadne-codegen + poetry run ariadne-codegen test: - pytest -s + poetry run pytest -s lint: - ruff check . --fix + poetry run ruff check . --fix -format: - ruff format \ No newline at end of file +format: remove_unused_imports + poetry run ruff format + +remove_unused_imports: + poetry run pycln --all . + +typecheck: + poetry run pyright \ No newline at end of file diff --git a/README.md b/README.md index 1268d5c..d81ba0d 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,14 @@ pip install cow_py Here's a simple example to get your hooves dirty: ```python -# TODO: this code is aspirational, this API doesn't exist -from cow_py.order_book import OrderBook -# Initialize the OrderBook -order_book = OrderBook() +from cow_py.order_book.api import OrderBookApi, UID + +# Initialize the OrderBookApi +order_book_api = OrderBookApi() # Fetch and display orders -orders = order_book.get_orders() +orders = order_book.get_order_by_uid(UID("0x...")) print(orders) ``` diff --git a/cow_py/codegen/__generated__/ComposableCow.py b/cow_py/codegen/__generated__/ComposableCow.py index c74935a..fdfcfa5 100644 --- a/cow_py/codegen/__generated__/ComposableCow.py +++ b/cow_py/codegen/__generated__/ComposableCow.py @@ -1,14 +1,16 @@ +from dataclasses import dataclass from typing import List, Tuple + from hexbytes import HexBytes -from cow_py.common.chains import Chain -from dataclasses import dataclass + from cow_py.codegen.components import ( - BaseMixin, BaseContract, - FileAbiLoader, + BaseMixin, ContractFactory, + FileAbiLoader, get_abi_file, ) +from cow_py.common.chains import Chain @dataclass @@ -18,6 +20,12 @@ class IConditionalOrder_ConditionalOrderParams: staticInput: HexBytes +@dataclass +class ComposableCoW_Proof: + location: int + data: HexBytes + + @dataclass class GPv2Order_Data: sellToken: str @@ -34,12 +42,6 @@ class GPv2Order_Data: buyTokenBalance: HexBytes -@dataclass -class ComposableCoW_Proof: - location: int - data: HexBytes - - class ComposableCowMixin(BaseMixin): def cabinet(self, str_arg_0: str, hexbytes_arg_0: HexBytes) -> HexBytes: return self.call_contract_method("cabinet", str_arg_0, hexbytes_arg_0) diff --git a/cow_py/codegen/__generated__/ExtensibleFallbackHandler.py b/cow_py/codegen/__generated__/ExtensibleFallbackHandler.py index 02a9279..2492af1 100644 --- a/cow_py/codegen/__generated__/ExtensibleFallbackHandler.py +++ b/cow_py/codegen/__generated__/ExtensibleFallbackHandler.py @@ -1,13 +1,15 @@ from typing import List + from hexbytes import HexBytes -from cow_py.common.chains import Chain + from cow_py.codegen.components import ( - BaseMixin, BaseContract, - FileAbiLoader, + BaseMixin, ContractFactory, + FileAbiLoader, get_abi_file, ) +from cow_py.common.chains import Chain class ExtensibleFallbackHandlerMixin(BaseMixin): diff --git a/cow_py/codegen/__generated__/Milkman.py b/cow_py/codegen/__generated__/Milkman.py index be4749d..5a35cee 100644 --- a/cow_py/codegen/__generated__/Milkman.py +++ b/cow_py/codegen/__generated__/Milkman.py @@ -1,12 +1,13 @@ from hexbytes import HexBytes -from cow_py.common.chains import Chain + from cow_py.codegen.components import ( - BaseMixin, BaseContract, - FileAbiLoader, + BaseMixin, ContractFactory, + FileAbiLoader, get_abi_file, ) +from cow_py.common.chains import Chain class MilkmanMixin(BaseMixin): diff --git a/cow_py/codegen/__generated__/TWAP.py b/cow_py/codegen/__generated__/TWAP.py index 2cb776c..877acc5 100644 --- a/cow_py/codegen/__generated__/TWAP.py +++ b/cow_py/codegen/__generated__/TWAP.py @@ -1,13 +1,22 @@ -from hexbytes import HexBytes -from cow_py.common.chains import Chain from dataclasses import dataclass + +from hexbytes import HexBytes + from cow_py.codegen.components import ( - BaseMixin, BaseContract, - FileAbiLoader, + BaseMixin, ContractFactory, + FileAbiLoader, get_abi_file, ) +from cow_py.common.chains import Chain + + +@dataclass +class IConditionalOrder_ConditionalOrderParams: + handler: str + salt: HexBytes + staticInput: HexBytes @dataclass diff --git a/cow_py/codegen/__init__.py b/cow_py/codegen/__init__.py index e69de29..00b8a0b 100644 --- a/cow_py/codegen/__init__.py +++ b/cow_py/codegen/__init__.py @@ -0,0 +1,5 @@ +from .abi_handler import ABIHandler + +__all__ = [ + "ABIHandler", +] diff --git a/cow_py/codegen/abi_handler.py b/cow_py/codegen/abi_handler.py index d514a5b..0bcac52 100644 --- a/cow_py/codegen/abi_handler.py +++ b/cow_py/codegen/abi_handler.py @@ -1,11 +1,12 @@ +import importlib.resources import re from typing import Any, Dict, List + from pybars import Compiler -from cow_py.codegen.components.abi_loader import FileAbiLoader -import importlib.resources + from cow_py.codegen.components import templates +from cow_py.codegen.components.abi_loader import FileAbiLoader from cow_py.codegen.components.templates import partials - from cow_py.codegen.solidity_converter import SolidityConverter CAMEL_TO_SNAKE_REGEX = re.compile( @@ -48,6 +49,12 @@ def _get_partials_files() -> str: return [str(x) for x in pkg_files.iterdir() if x.suffix == ".hbs"] # type: ignore +class ABIHandlerError(Exception): + """Raised when an error occurs in the ABI handler.""" + + pass + + class ABIHandler: """ Handles the generation of Python classes and methods from Ethereum contract ABIs. @@ -77,10 +84,15 @@ def generate(self) -> str: Returns: str: The generated Python code as a string. - """ - template_data = self._prepare_template_data() - return self._render_template(template_data) + Raises: + ABIHandlerError: If an error occurs during ABI processing or code generation. + """ + try: + template_data = self._prepare_template_data() + return self._render_template(template_data) + except Exception as e: + raise ABIHandlerError(f"Error generating code: {str(e)}") from e def _prepare_template_data(self) -> Dict[str, Any]: """ @@ -91,27 +103,46 @@ def _prepare_template_data(self) -> Dict[str, Any]: Returns: Dict[str, Any]: A dictionary containing the structured data for rendering. - """ - methods, data_classes, enums = [], [], [] - generated_structs, generated_enums = set(), set() - - abi = FileAbiLoader(self.abi_file_path).load_abi() - - for item in abi: - if item["type"] == "function": - methods.append(self._process_function(item)) - for param in item["inputs"] + item.get("outputs", []): - self._process_parameters( - param, data_classes, enums, generated_structs, generated_enums - ) - return { - "abiPath": self.abi_file_path, - "contractName": self.contract_name, - "methods": methods, - "dataClasses": data_classes, - "enums": enums, - } + Raises: + ABIHandlerError: If an error occurs during ABI processing. + """ + try: + methods, data_classes, enums = [], [], [] + generated_structs, generated_enums = set(), set() + + abi = FileAbiLoader(self.abi_file_path).load_abi() + + for item in abi: + if item["type"] == "function": + methods.append(self._process_function(item)) + for param in item["inputs"] + item.get("outputs", []): + self._process_parameters( + param, + data_classes, + enums, + generated_structs, + generated_enums, + ) + elif item["type"] == "event": + for param in item["inputs"]: + self._process_parameters( + param, + data_classes, + enums, + generated_structs, + generated_enums, + ) + + return { + "abiPath": self.abi_file_path, + "contractName": self.contract_name, + "methods": methods, + "dataClasses": data_classes, + "enums": enums, + } + except Exception as e: + raise ABIHandlerError(f"Error preparing template data: {str(e)}") from e def _process_parameters( self, param, data_classes, enums, generated_structs, generated_enums @@ -134,15 +165,11 @@ def _process_parameters( and param["internalType"] not in generated_enums ): enum_name = SolidityConverter._get_struct_name(param["internalType"]) - enums.append( - { - "name": enum_name, - "values": [ - {"name": "VALUE_1", "value": 1}, - {"name": "VALUE_2", "value": 2}, - ], - } - ) + enum_values = [ + {"name": item["name"], "value": item["value"]} + for item in param["components"] + ] + enums.append({"name": enum_name, "values": enum_values}) generated_enums.add(param["internalType"]) def _process_function(self, function_item: Dict[str, Any]) -> Dict[str, Any]: @@ -169,13 +196,6 @@ def _process_function(self, function_item: Dict[str, Any]) -> Dict[str, Any]: "originalName": original_name, } - def _process_enum(self, enum_item: Dict[str, Any]) -> Dict[str, Any]: - enum_name = enum_item["name"] - enum_values = [ - {"name": v["name"], "value": v["value"]} for v in enum_item["values"] - ] - return {"name": enum_name, "values": enum_values} - def _generate_function_input_args_with_types( self, function_item: Dict[str, Any] ) -> List[Dict[str, Any]]: diff --git a/cow_py/codegen/components/__init__.py b/cow_py/codegen/components/__init__.py index 7a8a9cc..df6ddb9 100644 --- a/cow_py/codegen/components/__init__.py +++ b/cow_py/codegen/components/__init__.py @@ -1,9 +1,10 @@ +from cow_py.codegen.components.abi_loader import FileAbiLoader from cow_py.codegen.components.base_contract import BaseContract +from cow_py.codegen.components.base_mixin import BaseMixin from cow_py.codegen.components.contract_factory import ContractFactory -from cow_py.codegen.components.abi_loader import FileAbiLoader from cow_py.codegen.components.contract_loader import ContractLoader -from cow_py.codegen.components.base_mixin import BaseMixin from cow_py.codegen.components.get_abi_file import get_abi_file +from cow_py.codegen.components.templates import partials __all__ = [ "BaseContract", @@ -12,4 +13,5 @@ "ContractLoader", "BaseMixin", "get_abi_file", + "partials", ] diff --git a/cow_py/codegen/components/abi_loader.py b/cow_py/codegen/components/abi_loader.py index e37cc64..4cfa24c 100644 --- a/cow_py/codegen/components/abi_loader.py +++ b/cow_py/codegen/components/abi_loader.py @@ -1,6 +1,6 @@ -from typing import List, Any -from abc import ABC, abstractmethod import json +from abc import ABC, abstractmethod +from typing import Any, List class AbiLoader(ABC): diff --git a/cow_py/codegen/components/base_contract.py b/cow_py/codegen/components/base_contract.py index bbb0451..38bd724 100644 --- a/cow_py/codegen/components/base_contract.py +++ b/cow_py/codegen/components/base_contract.py @@ -1,6 +1,13 @@ -from typing import Dict, List, Optional, Tuple, Any, Type -from cow_py.common.chains import Chain +from typing import Any, Dict, List, Optional, Tuple, Type + from cow_py.codegen.components.contract_loader import ContractLoader +from cow_py.common.chains import Chain + + +class BaseContractError(Exception): + """Raised when an error occurs in the BaseContract class.""" + + pass class BaseContract: @@ -22,20 +29,19 @@ def __new__(cls, address, chain, *args, **kwargs): cls._instances[key] = super(BaseContract, cls).__new__(cls) return cls._instances[key] - def __init__(self, address: str, chain: Chain, abi=None): + def __init__(self, address: str, chain: Chain, abi: List[Any] = None): """ - Initializes the BaseContract with a contract address, chain, and optionally an ABI file name. + Initializes the BaseContract with a contract address, chain, and optionally an ABI. :param address: The address of the contract on the specified chain :param chain: The chain the contract is deployed on - :param abi_file_name: The ABI file name of the contract, optional :param abi: The ABI of the contract, optional """ if not hasattr(self, "_initialized"): # Avoid re-initialization # Initialize the instance (only the first time) self.contract_loader = ContractLoader(chain) self.web3_contract = self.contract_loader.get_web3_contract( - address, self.ABI if abi is None else abi + address, abi or self.ABI or [] ) self._initialized = True @@ -50,10 +56,10 @@ def _function_exists_in_abi(self, function_name): :param function_name: The name of the function to check for :return: True if the function exists, False otherwise """ - for item in self.web3_contract.abi: - if item.get("type") == "function" and item.get("name") == function_name: - return True - return False + return any( + item.get("type") == "function" and item.get("name") == function_name + for item in self.web3_contract.abi + ) def _event_exists_in_abi(self, event_name): """ @@ -62,10 +68,10 @@ def _event_exists_in_abi(self, event_name): :param event_name: The name of the event to check for :return: True if the event exists, False otherwise """ - for item in self.web3_contract.abi: - if item.get("type") == "event" and item.get("name") == event_name: - return True - return False + return any( + item.get("type") == "event" and item.get("name") == event_name + for item in self.web3_contract.abi + ) def __getattr__(self, name): """ @@ -73,24 +79,31 @@ def __getattr__(self, name): :param name: The name of the attribute being accessed :return: The wrapped contract function if it exists, raises AttributeError otherwise + + Raises: + BaseContractError: If an error occurs while accessing the contract function. """ if name == "_initialized": # This is needed to avoid infinite recursion raise AttributeError(name) - if getattr(self.web3_contract, name, None): - return getattr(self.web3_contract, name) + try: + if hasattr(self.web3_contract, name): + return getattr(self.web3_contract, name) - if self._event_exists_in_abi(name): - # TODO: ability to get event signature hash - function = getattr(self.web3_contract.events, name) + if self._event_exists_in_abi(name): + return getattr(self.web3_contract.events, name) - if self._function_exists_in_abi(name): - function = getattr(self.web3_contract.functions, name) + if self._function_exists_in_abi(name): + function = getattr(self.web3_contract.functions, name) - def wrapped_call(*args, **kwargs): - return function(*args, **kwargs).call() + def wrapped_call(*args, **kwargs): + return function(*args, **kwargs).call() - return wrapped_call + return wrapped_call + except Exception as e: + raise BaseContractError( + f"Error accessing attribute {name}: {str(e)}" + ) from e raise AttributeError(f"{self.__class__.__name__} has no attribute {name}") diff --git a/cow_py/codegen/components/contract_factory.py b/cow_py/codegen/components/contract_factory.py index af3a5a9..ccfe8e7 100644 --- a/cow_py/codegen/components/contract_factory.py +++ b/cow_py/codegen/components/contract_factory.py @@ -1,7 +1,8 @@ from typing import Dict, Tuple, Type -from cow_py.common.chains import Chain + from cow_py.codegen.components.abi_loader import AbiLoader from cow_py.codegen.components.base_contract import BaseContract +from cow_py.common.chains import Chain class ContractFactory: diff --git a/cow_py/codegen/components/contract_loader.py b/cow_py/codegen/components/contract_loader.py index 4b1e822..aa68d52 100644 --- a/cow_py/codegen/components/contract_loader.py +++ b/cow_py/codegen/components/contract_loader.py @@ -1,6 +1,12 @@ from cow_py.web3.provider import Web3Provider +class ContractLoaderError(Exception): + """Raised when an error occurs in the ContractLoader class.""" + + pass + + class ContractLoader: """ A utility class to load contract ABIs and create web3 contract instances. @@ -22,10 +28,16 @@ def get_web3_contract(self, contract_address, abi=None): :param contract_address: The address of the contract. :param abi_file_name: The file name of the ABI, optional. :return: A web3 contract instance. + + Raises: + ContractLoaderError: If an error occurs while creating the web3 contract instance. """ - w3 = Web3Provider.get_instance(self.network) + try: + w3 = Web3Provider.get_instance(self.network) - return w3.eth.contract( - address=w3.to_checksum_address(contract_address), - abi=abi, - ) + return w3.eth.contract( + address=w3.to_checksum_address(contract_address), + abi=abi, + ) + except Exception as e: + raise ContractLoaderError(f"Error loading contract: {str(e)}") from e diff --git a/cow_py/codegen/example/Vault_types.py b/cow_py/codegen/example/Vault_types.py index 80a65a5..1104fd7 100644 --- a/cow_py/codegen/example/Vault_types.py +++ b/cow_py/codegen/example/Vault_types.py @@ -1,14 +1,16 @@ -from typing import List, Tuple, Any -from hexbytes import HexBytes -from cow_py.common.chains import Chain from dataclasses import dataclass from enum import Enum +from typing import Any, List, Tuple + +from hexbytes import HexBytes + from cow_py.codegen.components import ( - BaseMixin, BaseContract, - FileAbiLoader, + BaseMixin, ContractFactory, + FileAbiLoader, ) +from cow_py.common.chains import Chain # TODO: Enums must be fixed before using them. They currently only use placeholder values. diff --git a/cow_py/codegen/main.py b/cow_py/codegen/main.py index 2d041d6..15604e1 100644 --- a/cow_py/codegen/main.py +++ b/cow_py/codegen/main.py @@ -1,10 +1,8 @@ +import importlib.resources import os from cow_py.codegen.abi_handler import ABIHandler - - from cow_py.contracts import abi -import importlib.resources def get_all_abis(): diff --git a/cow_py/codegen/solidity_converter.py b/cow_py/codegen/solidity_converter.py index f76023c..90766f0 100644 --- a/cow_py/codegen/solidity_converter.py +++ b/cow_py/codegen/solidity_converter.py @@ -1,4 +1,6 @@ -# Constants +import re +from typing import Optional + SOLIDITY_TO_PYTHON_TYPES = { "address": "str", "bool": "bool", @@ -8,17 +10,17 @@ "int": "int", } DYNAMIC_SOLIDITY_TYPES = { - f"{prefix}{i*8 if prefix != 'bytes' else i}": "int" - if prefix != "bytes" - else "HexBytes" + f"{prefix}{i*8 if prefix != 'bytes' else i}": ( + "int" if prefix != "bytes" else "HexBytes" + ) for prefix in ["uint", "int", "bytes"] for i in range(1, 33) } SOLIDITY_TO_PYTHON_TYPES.update(DYNAMIC_SOLIDITY_TYPES) -class InvalidABIError(Exception): - """Raised when an invalid ABI is provided.""" +class SolidityConverterError(Exception): + """Raised when an error occurs in the SolidityConverter.""" pass @@ -44,7 +46,14 @@ def _get_struct_name(internal_type: str) -> str: Returns: str: The extracted name of the struct. + + Raises: + SolidityConverterError: If the internal type is not in the expected format. """ + if not internal_type or "struct " not in internal_type: + raise SolidityConverterError( + f"Invalid internal type for struct: {internal_type}" + ) return internal_type.replace("struct ", "").replace(".", "_").replace("[]", "") @classmethod @@ -59,14 +68,32 @@ def convert_type(cls, solidity_type: str, internal_type: str) -> str: Returns: str: The Python type equivalent to the given Solidity type. """ - if internal_type and "enum" in internal_type: - return internal_type.split("enum")[-1].split(".")[-1].strip() - if "[]" in solidity_type: - base_type = solidity_type.replace("[]", "") - return f'List[{SOLIDITY_TO_PYTHON_TYPES.get(base_type, "Any")}]' - elif "[" in solidity_type and "]" in solidity_type: - base_type = solidity_type.split("[")[0] - return f'List[{SOLIDITY_TO_PYTHON_TYPES.get(base_type, "Any")}]' + if re.search(r"enum", internal_type) or (re.search(r"enum", solidity_type)): + return cls._extract_enum_name(internal_type, solidity_type) elif solidity_type == "tuple": return cls._get_struct_name(internal_type) - return SOLIDITY_TO_PYTHON_TYPES.get(solidity_type, "Any") + else: + return cls._convert_array_or_basic_type(solidity_type) + + @staticmethod + def _extract_enum_name( + internal_type: Optional[str], solidity_type: Optional[str] = None + ) -> str: + if internal_type and re.search(r"enum", internal_type): + return internal_type.replace("enum ", "").replace(".", "_") + elif solidity_type and re.search(r"enum", solidity_type): + return solidity_type.replace("enum ", "").replace(".", "_") + raise SolidityConverterError(f"Invalid internal type for enum: {internal_type}") + + @staticmethod + def _convert_array_or_basic_type(solidity_type: str) -> str: + array_match = re.match(r"(.+?)(\[\d*\])", solidity_type) + if array_match: + base_type, array_size = array_match.groups() + if array_size == "[]": + return f'List[{SOLIDITY_TO_PYTHON_TYPES.get(base_type, "Any")}]' + else: + size = int(array_size[1:-1]) + return f'Tuple[{", ".join([SOLIDITY_TO_PYTHON_TYPES.get(base_type, "Any")] * size)}]' + else: + return SOLIDITY_TO_PYTHON_TYPES.get(solidity_type, "Any") diff --git a/cow_py/common/api/api_base.py b/cow_py/common/api/api_base.py new file mode 100644 index 0000000..545150e --- /dev/null +++ b/cow_py/common/api/api_base.py @@ -0,0 +1,85 @@ +from abc import ABC +from typing import Any, Optional + +import httpx + +from cow_py.common.api.decorators import rate_limitted, with_backoff +from cow_py.common.config import SupportedChainId + +Context = dict[str, Any] + + +class APIConfig(ABC): + """Base class for API configuration with common functionality.""" + + config_map = {} + + def __init__( + self, chain_id: SupportedChainId, base_context: Optional[Context] = None + ): + self.chain_id = chain_id + self.context = base_context or {} + + def get_base_url(self) -> str: + return self.config_map.get( + self.chain_id, "default URL if chain_id is not found" + ) + + def get_context(self) -> Context: + return {"base_url": self.get_base_url(), **self.context} + + +class RequestStrategy: + async def make_request(self, client, url, method, **request_kwargs): + headers = { + "accept": "application/json", + "content-type": "application/json", + } + + return await client.request( + url=url, headers=headers, method=method, **request_kwargs + ) + + +class ResponseAdapter: + async def adapt_response(self, _response): + raise NotImplementedError() + + +class RequestBuilder: + def __init__(self, strategy, response_adapter): + self.strategy = strategy + self.response_adapter = response_adapter + + async def execute(self, client, url, method, **kwargs): + response = await self.strategy.make_request(client, url, method, **kwargs) + return self.response_adapter.adapt_response(response) + + +class JsonResponseAdapter(ResponseAdapter): + def adapt_response(self, response): + if response.headers.get("content-type") == "application/json": + return response.json() + else: + return response.text + + +class ApiBase: + """Base class for APIs utilizing configuration and request execution.""" + + def __init__(self, config: APIConfig): + self.config = config + + @with_backoff() + @rate_limitted() + async def _fetch(self, path, method="GET", **kwargs): + url = self.config.get_base_url() + path + + del kwargs["context_override"] + + async with httpx.AsyncClient() as client: + builder = RequestBuilder( + RequestStrategy(), + JsonResponseAdapter(), + ) + return await builder.execute(client, url, method, **kwargs) diff --git a/cow_py/common/api/decorators.py b/cow_py/common/api/decorators.py new file mode 100644 index 0000000..305121a --- /dev/null +++ b/cow_py/common/api/decorators.py @@ -0,0 +1,58 @@ +import backoff +import httpx +from aiolimiter import AsyncLimiter + +DEFAULT_LIMITER_OPTIONS = {"rate": 5, "per": 1.0} + +DEFAULT_BACKOFF_OPTIONS = { + "max_tries": 10, + "max_time": None, + "jitter": None, +} + + +def dig(self, *keys): + try: + for key in keys: + self = self[key] + return self + except KeyError: + return None + + +def with_backoff(): + def decorator(func): + async def wrapper(*args, **kwargs): + backoff_opts = dig(kwargs, "context_override", "backoff_opts") + + if backoff_opts is None: + internal_backoff_opts = DEFAULT_BACKOFF_OPTIONS + else: + internal_backoff_opts = backoff_opts + + @backoff.on_exception( + backoff.expo, httpx.HTTPStatusError, **internal_backoff_opts + ) + async def closure(): + return await func(*args, **kwargs) + + return await closure() + + return wrapper + + return decorator + + +def rate_limitted( + rate=DEFAULT_LIMITER_OPTIONS["rate"], per=DEFAULT_LIMITER_OPTIONS["per"] +): + limiter = AsyncLimiter(rate, per) + + def decorator(func): + async def wrapper(*args, **kwargs): + async with limiter: + return await func(*args, **kwargs) + + return wrapper + + return decorator diff --git a/cow_py/common/chains/__init__.py b/cow_py/common/chains/__init__.py index 3f99f60..bf21c1d 100644 --- a/cow_py/common/chains/__init__.py +++ b/cow_py/common/chains/__init__.py @@ -19,5 +19,13 @@ def __init__(self, id: int, network_name: str, explorer_url: str) -> None: def name(self) -> str: return self.network_name + @property + def explorer(self) -> str: + return self.explorer_url + + @property + def chain_id(self) -> int: + return self.id + SUPPORTED_CHAINS = {chain for chain in Chain} diff --git a/cow_py/common/config.py b/cow_py/common/config.py index c82a166..ae4316b 100644 --- a/cow_py/common/config.py +++ b/cow_py/common/config.py @@ -1,4 +1,35 @@ +from dataclasses import dataclass from enum import Enum +from typing import Dict, Optional + + +class SupportedChainId(Enum): + MAINNET = 1 + GNOSIS_CHAIN = 100 + SEPOLIA = 11155111 + + +class CowEnv(Enum): + PROD = "prod" + STAGING = "staging" + + +ApiBaseUrls = Dict[SupportedChainId, str] + + +@dataclass +class ApiContext: + chain_id: SupportedChainId + env: CowEnv + base_urls: Optional[ApiBaseUrls] = None + max_tries: Optional[int] = 5 + + +# Define the list of available environments. +ENVS_LIST = [CowEnv.PROD, CowEnv.STAGING] + +# Define the default CoW Protocol API context. +DEFAULT_COW_API_CONTEXT = ApiContext(env=CowEnv.PROD, chain_id=SupportedChainId.MAINNET) class IPFSConfig(Enum): diff --git a/cow_py/common/constants.py b/cow_py/common/constants.py index 29ca7c3..2978a26 100644 --- a/cow_py/common/constants.py +++ b/cow_py/common/constants.py @@ -1,5 +1,6 @@ from enum import Enum from typing import Dict + from .chains import Chain """ @@ -17,14 +18,14 @@ class CowContractAddress(Enum): EXTENSIBLE_FALLBACK_HANDLER = "0x2f55e8b20D0B9FEFA187AA7d00B6Cbe563605bF5" -def map_address_to_supported_networks(address) -> Dict[Chain, str]: +def map_address_to_supported_networks(address) -> Dict[int, str]: """ Maps a given address to all supported networks. :param address: The address to be mapped. :return: A dictionary mapping the address to each supported chain. """ - return {chain_id: address for chain_id in Chain} + return {chain.chain_id: address for chain in Chain} COW_PROTOCOL_SETTLEMENT_CONTRACT_CHAIN_ADDRESS_MAP = map_address_to_supported_networks( diff --git a/cow_py/contracts/domain.py b/cow_py/contracts/domain.py new file mode 100644 index 0000000..51872df --- /dev/null +++ b/cow_py/contracts/domain.py @@ -0,0 +1,29 @@ +from dataclasses import dataclass +from typing import Optional + +from cow_py.common.chains import Chain + + +@dataclass +class TypedDataDomain: + name: str + version: str + chainId: int + verifyingContract: str + salt: Optional[str] = None + + +def domain(chain: Chain, verifying_contract: str) -> TypedDataDomain: + """ + Return the Gnosis Protocol v2 domain used for signing. + + :param chain: The EIP-155 chain ID. + :param verifying_contract: The address of the contract that will verify the signature. + :return: An EIP-712 compatible typed domain data. + """ + return TypedDataDomain( + name="Gnosis Protocol", + version="v2", + chainId=chain.chain_id, + verifyingContract=verifying_contract, + ) diff --git a/cow_py/contracts/order.py b/cow_py/contracts/order.py new file mode 100644 index 0000000..173e2f8 --- /dev/null +++ b/cow_py/contracts/order.py @@ -0,0 +1,340 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Literal, Optional, Union + +from eth_account.messages import _hash_eip191_message, encode_typed_data +from eth_typing import Hash32, HexStr +from eth_utils.conversions import to_bytes, to_hex + + +@dataclass +class Order: + # Sell token address. + sellToken: str + # Buy token address. + buyToken: str + # An optional address to receive the proceeds of the trade instead of the + # owner (i.e. the order signer). + receiver: str + # The order sell amount. + # + # For fill or kill sell orders, this amount represents the exact sell amount + # that will be executed in the trade. For fill or kill buy orders, this + # amount represents the maximum sell amount that can be executed. For partial + # fill orders, this represents a component of the limit price fraction. + # + sellAmount: int + # The order buy amount. + # + # For fill or kill sell orders, this amount represents the minimum buy amount + # that can be executed in the trade. For fill or kill buy orders, this amount + # represents the exact buy amount that will be executed. For partial fill + # orders, this represents a component of the limit price fraction. + # + buyAmount: int + # The timestamp this order is valid until + validTo: int + # Arbitrary application specific data that can be added to an order. This can + # also be used to ensure uniqueness between two orders with otherwise the + # exact same parameters. + appData: str + # Fee to give to the protocol. + feeAmount: int + # The order kind. + kind: str + # Specifies whether or not the order is partially fillable. + partiallyFillable: bool = False + # Specifies how the sell token balance will be withdrawn. It can either be + # taken using ERC20 token allowances made directly to the Vault relayer + # (default) or using Balancer Vault internal or external balances. + sellTokenBalance: Optional[str] = None + # Specifies how the buy token balance will be paid. It can either be paid + # directly in ERC20 tokens (default) in Balancer Vault internal balances. + buyTokenBalance: Optional[str] = None + + +# Gnosis Protocol v2 order cancellation data. +@dataclass +class OrderCancellations: + orderUids: bytearray + + +# Marker address to indicate that an order is buying Ether. +# +# Note that this address is only has special meaning in the `buyToken` and will +# be treated as a ERC20 token address in the `sellToken` position, causing the +# settlement to revert. +BUY_ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" + +# /** +# * Gnosis Protocol v2 order flags. +# */ +# export type OrderFlags = Pick< +# Order, +# "kind" | "partiallyFillable" | "sellTokenBalance" | "buyTokenBalance" +# >; + +Timestamp = Union[int, int] + +BytesLike = Union[str, bytes, HexStr] + +HashLike = Union[BytesLike, int] + + +class OrderKind(Enum): + SELL = "sell" + BUY = "buy" + + +class OrderBalance(Enum): + # Use ERC20 token balances. + ERC20 = "erc20" + # Use Balancer Vault external balances. + + # This can only be specified specified for the sell balance and allows orders + # to re-use Vault ERC20 allowances. When specified for the buy balance, it + # will be treated as {@link OrderBalance.ERC20}. + EXTERNAL = "external" + # Use Balancer Vault internal balances. + INTERNAL = "internal" + + +# /** +# * The EIP-712 type fields definition for a Gnosis Protocol v2 order. +# */ +ORDER_TYPE_FIELDS = [ + dict(name="sellToken", type="address"), + dict(name="buyToken", type="address"), + dict(name="receiver", type="address"), + dict(name="sellAmount", type="uint256"), + dict(name="buyAmount", type="uint256"), + dict(name="validTo", type="uint32"), + dict(name="appData", type="bytes32"), + dict(name="feeAmount", type="uint256"), + dict(name="kind", type="string"), + dict(name="partiallyFillable", type="bool"), + dict(name="sellTokenBalance", type="string"), + dict(name="buyTokenBalance", type="string"), +] +# The EIP-712 type fields definition for a Gnosis Protocol v2 order. +CANCELLATIONS_TYPE_FIELDS = [ + dict(name="orderUids", type="bytes[]"), +] + +# The EIP-712 type hash for a Gnosis Protocol v2 order. + +# ORDER_TYPE_HASH = +# export const ORDER_TYPE_HASH = ethers.utils.id( +# `Order(${ORDER_TYPE_FIELDS.map(({ name, type }) => `${type} ${name}`).join( +# ",", +# )})`, +# ); + + +# export function timestamp(t: Timestamp): number { +# return typeof t === "number" ? t : ~~(t.getTime() / 1000); +# } +def timestamp(t: int) -> int: + return t + + +def hashify(h: Union[int, str, bytes]) -> str: + """ + Normalizes an app data value to a 32-byte hash. + :param h: A hash-like value to normalize. Can be an integer, hexadecimal string, or bytes. + :return: A 32-byte hash encoded as a hex-string. + """ + if isinstance(h, int): + # Convert the integer to a hexadecimal string and pad it to 64 characters + return f"0x{h:064x}" + elif isinstance(h, str): + # Convert string to bytes, then pad it to 32 bytes (64 hex characters) + return to_hex(to_bytes(hexstr=h).rjust(32, b"\0")) + elif isinstance(h, bytes): + # Pad the bytes to 32 bytes (64 hex characters) + return to_hex(h.rjust(32, b"\0")) + else: + raise ValueError("Input must be an integer, a hexadecimal string, or bytes.") + + +def normalize_buy_token_balance( + balance: Optional[str], +) -> Literal["erc20", "internal"]: + """ + Normalizes the balance configuration for a buy token. + + :param balance: The balance configuration. + :return: The normalized balance configuration. + """ + if balance in [None, OrderBalance.ERC20.value, OrderBalance.EXTERNAL.value]: + return OrderBalance.ERC20.value + elif balance == OrderBalance.INTERNAL: + return OrderBalance.INTERNAL.value + else: + raise ValueError(f"Invalid order balance {balance}") + + +# /** +# * Normalized representation of an {@link Order} for EIP-712 operations. +# */ +# export type NormalizedOrder = Omit< +# Order, +# "validTo" | "appData" | "kind" | "sellTokenBalance" | "buyTokenBalance" +# > & { +# receiver: string; +# validTo: number; +# appData: string; +# kind: "sell" | "buy"; +# sellTokenBalance: "erc20" | "external" | "internal"; +# buyTokenBalance: "erc20" | "internal"; +# }; + + +ZERO_ADDRESS = "0x" + "00" * 20 + + +def normalize_order(order: Order): + if order.receiver == ZERO_ADDRESS: + raise ValueError("receiver cannot be address(0)") + + return { + "sellToken": order.sellToken, + "buyToken": order.buyToken, + "receiver": order.receiver if order.receiver else ZERO_ADDRESS, + "sellAmount": order.sellAmount, + "buyAmount": order.buyAmount, + "validTo": timestamp(order.validTo), + "appData": hashify(order.appData), + "feeAmount": order.feeAmount, + "kind": order.kind, + "partiallyFillable": order.partiallyFillable, + "sellTokenBalance": order.sellTokenBalance + if order.sellTokenBalance + else OrderBalance.ERC20.value, + "buyTokenBalance": normalize_buy_token_balance(order.buyTokenBalance), + } + + +def hash_typed_data(domain, types, data) -> Hash32: + """ + Compute the 32-byte signing hash for the specified order. + + :param domain: The EIP-712 domain separator to compute the hash for. + :param types: The typed data types. + :param data: The data to compute the digest for. + :return: Hex-encoded 32-byte order digest. + """ + encoded_data = encode_typed_data( + domain_data=domain, message_types=types, message_data=data + ) + return _hash_eip191_message(encoded_data) + + +def hash_order(domain, order): + """ + Compute the 32-byte signing hash for the specified order. + + :param domain: The EIP-712 domain separator to compute the hash for. + :param order: The order to compute the digest for. + :return: Hex-encoded 32-byte order digest. + """ + return hash_typed_data(domain, ORDER_TYPE_FIELDS, normalize_order(order)) + + +def hash_order_cancellation(domain, order_uid) -> str: + """ + Compute the 32-byte signing hash for the specified cancellation. + + :param domain: The EIP-712 domain separator to compute the hash for. + :param order_uid: The unique identifier of the order to cancel. + :return: Hex-encoded 32-byte order digest. + """ + return hash_order_cancellations(domain, [order_uid]) + + +def hash_order_cancellations(domain_data, order_uids) -> str: + """ + Compute the 32-byte signing hash for the specified order cancellations. + + :param domain_data: The EIP-712 domain separator to compute the hash for. + :param order_uids: The unique identifiers of the orders to cancel. + :return: Hex-encoded 32-byte order digest. + """ + return _hash_eip191_message( + encode_typed_data( + domain_data, + message_types={"OrderCancellations": CANCELLATIONS_TYPE_FIELDS}, + message_data={"orderUids": order_uids}, + ) + ).hex() + + +# The byte length of an order UID. +ORDER_UID_LENGTH = 56 + + +@dataclass +class OrderUidParams: + # The EIP-712 order struct hash. + orderDigest: str + # The owner of the order. + owner: str + # The timestamp this order is valid until. + validTo: int + + +# /** +# * Computes the order UID for an order and the given owner. +# */ +# export function computeOrderUid( +# domain: TypedDataDomain, +# order: Order, +# owner: string, +# ): string { +# return packOrderUidParams({ +# orderDigest: hashOrder(domain, order), +# owner, +# validTo: order.validTo, +# }); +# } + +# /** +# * Compute the unique identifier describing a user order in the settlement +# * contract. +# * +# * @param OrderUidParams The parameters used for computing the order's unique +# * identifier. +# * @returns A string that unequivocally identifies the order of the user. +# */ +# export function packOrderUidParams({ +# orderDigest, +# owner, +# validTo, +# }: OrderUidParams): string { +# return ethers.utils.solidityPack( +# ["bytes32", "address", "uint32"], +# [orderDigest, owner, timestamp(validTo)], +# ); +# } + +# /** +# * Extracts the order unique identifier parameters from the specified bytes. +# * +# * @param orderUid The order UID encoded as a hexadecimal string. +# * @returns The extracted order UID parameters. +# */ +# export function extractOrderUidParams(orderUid: string): OrderUidParams { +# const bytes = ethers.utils.arrayify(orderUid); +# if (bytes.length != ORDER_UID_LENGTH) { +# throw new Error("invalid order UID length"); +# } + +# const view = new DataView(bytes.buffer); +# return { +# orderDigest: ethers.utils.hexlify(bytes.subarray(0, 32)), +# owner: ethers.utils.getAddress( +# ethers.utils.hexlify(bytes.subarray(32, 52)), +# ), +# validTo: view.getUint32(52), +# }; +# } diff --git a/cow_py/contracts/sign.py b/cow_py/contracts/sign.py new file mode 100644 index 0000000..4217527 --- /dev/null +++ b/cow_py/contracts/sign.py @@ -0,0 +1,104 @@ +from enum import IntEnum +from typing import List, NamedTuple, Union + +from eth_account import Account +from eth_account.datastructures import SignedMessage +from eth_account.signers.local import LocalAccount +from eth_utils.conversions import to_hex +from eth_utils.crypto import keccak +from web3 import Web3 + +from cow_py.contracts.order import ( + CANCELLATIONS_TYPE_FIELDS, + ORDER_TYPE_FIELDS, + Order, + hash_typed_data, + normalize_order, +) + +EIP1271_MAGICVALUE = to_hex(keccak(text="isValidSignature(bytes32,bytes)"))[:10] +PRE_SIGNED = to_hex(keccak(text="GPv2Signing.Scheme.PreSign")) + + +class SigningScheme(IntEnum): + # The EIP-712 typed data signing scheme. This is the preferred scheme as it + # provides more infomation to wallets performing the signature on the data + # being signed. + # + # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#definition-of-domainseparator + EIP712 = 0b00 + # Message signed using eth_sign RPC call. + ETHSIGN = 0b01 + # Smart contract signatures as defined in EIP-1271. + EIP1271 = 0b10 + # Pre-signed order. + PRESIGN = 0b11 + + +class EcdsaSignature(NamedTuple): + scheme: SigningScheme + data: str + + +class Eip1271SignatureData(NamedTuple): + verifier: str + signature: bytes + + +class Eip1271Signature(NamedTuple): + scheme: SigningScheme + data: Eip1271SignatureData + + +class PreSignSignature(NamedTuple): + scheme: SigningScheme + data: str + + +Signature = Union[EcdsaSignature, Eip1271Signature, PreSignSignature] + + +def ecdsa_sign_typed_data( + scheme, owner: LocalAccount, domain_data, message_types, message_data +) -> SignedMessage: + return Account._sign_hash( + hash_typed_data(domain_data, message_types, message_data), owner.key + ) + + +def sign_order( + domain, order: Order, owner: LocalAccount, scheme: SigningScheme +) -> EcdsaSignature: + normalized_order = normalize_order(order) + signed_data = ecdsa_sign_typed_data( + scheme, owner, domain, {"Order": ORDER_TYPE_FIELDS}, normalized_order + ) + return EcdsaSignature( + scheme=scheme, + data=signed_data.signature.hex(), + ) + + +def sign_order_cancellation(domain, order_uid: Union[str, bytes], owner, scheme): + return sign_order_cancellations(domain, [order_uid], owner, scheme) + + +def sign_order_cancellations( + domain, order_uids: List[Union[str, bytes]], owner, scheme +): + data = {"orderUids": order_uids} + types = {"OrderCancellations": CANCELLATIONS_TYPE_FIELDS} + + signed_data = ecdsa_sign_typed_data(scheme, owner, domain, types, data) + + return EcdsaSignature(scheme=scheme, data=signed_data.signature.hex()) + + +def encode_eip1271_signature_data(verifier, signature): + return Web3.solidity_keccak(["address", "bytes"], [verifier, signature]) + + +def decode_eip1271_signature_data(signature): + arrayified_signature = bytes.fromhex(signature[2:]) # Removing '0x' + verifier = Web3.to_checksum_address(arrayified_signature[:20].hex()) + return Eip1271SignatureData(verifier, arrayified_signature[20:]) diff --git a/cow_py/order_book/api.py b/cow_py/order_book/api.py new file mode 100644 index 0000000..c99b394 --- /dev/null +++ b/cow_py/order_book/api.py @@ -0,0 +1,203 @@ +import json +from typing import Any, Dict, List + +from cow_py.common.api.api_base import ApiBase, Context +from cow_py.common.config import SupportedChainId +from cow_py.order_book.config import OrderBookAPIConfigFactory +from typing import Union +from cow_py.order_book.generated.model import OrderQuoteSide2, OrderQuoteValidity2 + +from .generated.model import ( + UID, + Address, + AppDataHash, + AppDataObject, + NativePriceResponse, + Order, + OrderCancellation, + OrderCreation, + OrderQuoteRequest, + OrderQuoteResponse, + OrderQuoteSide, + OrderQuoteSide1, + OrderQuoteSide3, + OrderQuoteValidity, + OrderQuoteValidity1, + SolverCompetitionResponse, + TotalSurplus, + Trade, + TransactionHash, +) + + +class OrderBookApi(ApiBase): + def __init__( + self, + config=OrderBookAPIConfigFactory.get_config("prod", SupportedChainId.MAINNET), + ): + self.config = config + + async def get_version(self, context_override: Context = {}) -> str: + return await self._fetch( + path="/api/v1/version", context_override=context_override + ) + + async def get_trades_by_owner( + self, owner: Address, context_override: Context = {} + ) -> List[Trade]: + response = await self._fetch( + path="/api/v1/trades", + params={"owner": owner}, + context_override=context_override, + ) + return [Trade(**trade) for trade in response] + + async def get_trades_by_order_uid( + self, order_uid: UID, context_override: Context = {} + ) -> List[Trade]: + response = await self._fetch( + path="/api/v1/trades", + params={"order_uid": order_uid}, + context_override=context_override, + ) + return [Trade(**trade) for trade in response] + + async def get_orders_by_owner( + self, + owner: Address, + limit: int = 1000, + offset: int = 0, + context_override: Context = {}, + ) -> List[Order]: + return [ + Order(**order) + for order in await self._fetch( + path=f"/api/v1/account/{owner}/orders", + params={"limit": limit, "offset": offset}, + context_override=context_override, + ) + ] + + async def get_order_by_uid( + self, order_uid: UID, context_override: Context = {} + ) -> Order: + response = await self._fetch( + path=f"/api/v1/orders/{order_uid}", + context_override=context_override, + ) + return Order(**response) + + def get_order_link(self, order_uid: UID) -> str: + return self.config.get_base_url() + f"/api/v1/orders/{order_uid.root}" + + async def get_tx_orders( + self, tx_hash: TransactionHash, context_override: Context = {} + ) -> List[Order]: + response = await self._fetch( + path=f"/api/v1/transactions/{tx_hash}/orders", + context_override=context_override, + ) + return [Order(**order) for order in response] + + async def get_native_price( + self, tokenAddress: Address, context_override: Context = {} + ) -> NativePriceResponse: + response = await self._fetch( + path=f"/api/v1/token/{tokenAddress}/native_price", + context_override=context_override, + ) + return NativePriceResponse(**response) + + async def get_total_surplus( + self, user: Address, context_override: Context = {} + ) -> TotalSurplus: + response = await self._fetch( + path=f"/api/v1/users/{user}/total_surplus", + context_override=context_override, + ) + return TotalSurplus(**response) + + async def get_app_data( + self, app_data_hash: AppDataHash, context_override: Context = {} + ) -> Dict[str, Any]: + return await self._fetch( + path=f"/api/v1/app_data/{app_data_hash}", + context_override=context_override, + ) + + async def get_solver_competition( + self, action_id: Union[int, str] = "latest", context_override: Context = {} + ) -> SolverCompetitionResponse: + response = await self._fetch( + path=f"/api/v1/solver_competition/{action_id}", + context_override=context_override, + ) + return SolverCompetitionResponse(**response) + + async def get_solver_competition_by_tx_hash( + self, tx_hash: TransactionHash, context_override: Context = {} + ) -> SolverCompetitionResponse: + response = await self._fetch( + path=f"/api/v1/solver_competition/by_tx_hash/{tx_hash}", + context_override=context_override, + ) + return SolverCompetitionResponse(**response) + + async def post_quote( + self, + request: OrderQuoteRequest, + side: Union[OrderQuoteSide, OrderQuoteSide1, OrderQuoteSide2, OrderQuoteSide3], + validity: Union[ + OrderQuoteValidity, OrderQuoteValidity1, OrderQuoteValidity2 + ] = OrderQuoteValidity1(validTo=None), + context_override: Context = {}, + ) -> OrderQuoteResponse: + response = await self._fetch( + path="/api/v1/quote", + json={ + **request.model_dump(by_alias=True), + # side object need to be converted to json first to avoid on kind type + **json.loads(side.model_dump_json()), + **validity.model_dump(), + }, + context_override=context_override, + method="POST", + ) + return OrderQuoteResponse(**response) + + async def post_order(self, order: OrderCreation, context_override: Context = {}): + response = await self._fetch( + path="/api/v1/orders", + json=json.loads(order.model_dump_json(by_alias=True)), + context_override=context_override, + method="POST", + ) + return UID(response) + + async def delete_order( + self, + orders_cancelation: OrderCancellation, + context_override: Context = {}, + ): + response = await self._fetch( + path="/api/v1/orders", + json=orders_cancelation.model_dump_json(), + context_override=context_override, + method="DELETE", + ) + return UID(response) + + async def put_app_data( + self, + app_data: AppDataObject, + app_data_hash: str = "", + context_override: Context = {}, + ) -> AppDataHash: + app_data_hash_url = app_data_hash if app_data_hash else "" + response = await self._fetch( + path=f"/api/v1/app_data/{app_data_hash_url}", + json=app_data.model_dump_json(), + context_override=context_override, + method="PUT", + ) + return AppDataHash(response) diff --git a/cow_py/order_book/config.py b/cow_py/order_book/config.py new file mode 100644 index 0000000..1953ca7 --- /dev/null +++ b/cow_py/order_book/config.py @@ -0,0 +1,39 @@ +from typing import Dict, Literal, Type + +from cow_py.common.api.api_base import APIConfig +from cow_py.common.config import SupportedChainId + + +class ProdAPIConfig(APIConfig): + config_map = { + SupportedChainId.MAINNET: "https://api.cow.fi/mainnet", + SupportedChainId.GNOSIS_CHAIN: "https://api.cow.fi/xdai", + SupportedChainId.SEPOLIA: "https://api.cow.fi/sepolia", + } + + +class StagingAPIConfig(APIConfig): + config_map = { + SupportedChainId.MAINNET: "https://barn.api.cow.fi/mainnet", + SupportedChainId.GNOSIS_CHAIN: "https://barn.api.cow.fi/xdai", + SupportedChainId.SEPOLIA: "https://barn.api.cow.fi/sepolia", + } + + +Envs = Literal["prod", "staging"] + + +class OrderBookAPIConfigFactory: + config_classes: Dict[Envs, Type[APIConfig]] = { + "prod": ProdAPIConfig, + "staging": StagingAPIConfig, + } + + @staticmethod + def get_config(env: Envs, chain_id: SupportedChainId) -> APIConfig: + config_class = OrderBookAPIConfigFactory.config_classes.get(env) + + if config_class: + return config_class(chain_id) + else: + raise ValueError("Unknown environment") diff --git a/cow_py/order_book/__generated__/model.py b/cow_py/order_book/generated/model.py similarity index 99% rename from cow_py/order_book/__generated__/model.py rename to cow_py/order_book/generated/model.py index 21ecee8..5f5188f 100644 --- a/cow_py/order_book/__generated__/model.py +++ b/cow_py/order_book/generated/model.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: https://raw.githubusercontent.com/cowprotocol/services/v2.245.1/crates/orderbook/openapi.yml -# timestamp: 2024-02-26T14:06:01+00:00 +# timestamp: 2024-04-12T14:44:16+00:00 from __future__ import annotations diff --git a/cow_py/subgraph/client/async_base_client.py b/cow_py/subgraph/client/async_base_client.py index 311e672..b9f1f6b 100644 --- a/cow_py/subgraph/client/async_base_client.py +++ b/cow_py/subgraph/client/async_base_client.py @@ -18,10 +18,8 @@ ) try: - from websockets.client import ( # type: ignore[import-not-found,unused-ignore] - WebSocketClientProtocol, - connect as ws_connect, - ) + from websockets.client import WebSocketClientProtocol + from websockets.client import connect as ws_connect # type: ignore[import-not-found,unused-ignore] from websockets.typing import ( # type: ignore[import-not-found,unused-ignore] Data, Origin, diff --git a/cow_py/subgraph/client/base_model.py b/cow_py/subgraph/client/base_model.py index 76b8487..a93b416 100644 --- a/cow_py/subgraph/client/base_model.py +++ b/cow_py/subgraph/client/base_model.py @@ -2,7 +2,8 @@ from io import IOBase -from pydantic import BaseModel as PydanticBaseModel, ConfigDict +from pydantic import BaseModel as PydanticBaseModel +from pydantic import ConfigDict class UnsetType: diff --git a/cow_py/subgraph/deployments.py b/cow_py/subgraph/deployments.py index 335a814..ce98ebc 100644 --- a/cow_py/subgraph/deployments.py +++ b/cow_py/subgraph/deployments.py @@ -1,7 +1,8 @@ -from cow_py.common.chains import Chain from dataclasses import dataclass from enum import Enum +from cow_py.common.chains import Chain + class SubgraphEnvironment(Enum): PRODUCTION = "production" diff --git a/cow_py/web3/provider.py b/cow_py/web3/provider.py index fc5a95d..7087d24 100644 --- a/cow_py/web3/provider.py +++ b/cow_py/web3/provider.py @@ -1,6 +1,7 @@ from typing import Dict import web3 + from cow_py.common.chains import Chain DEFAULT_PROVIDER_NETWORK_MAPPING = { diff --git a/cow_py/order_signing/__init__.py b/examples/__init__.py similarity index 100% rename from cow_py/order_signing/__init__.py rename to examples/__init__.py diff --git a/examples/order_posting_e2e.py b/examples/order_posting_e2e.py new file mode 100644 index 0000000..5dc9842 --- /dev/null +++ b/examples/order_posting_e2e.py @@ -0,0 +1,120 @@ +# To run this test you will need to fill the .env file with the necessary variables (see .env.example). +# You will also need to have enough funds in you wallet of the sell token to create the order. +# The funds have to already be approved to the CoW Swap Vault Relayer + +import asyncio +import json +import os +from dataclasses import asdict + +from web3 import Account + +from cow_py.common.chains import Chain +from cow_py.common.config import SupportedChainId +from cow_py.common.constants import CowContractAddress +from cow_py.contracts.domain import domain +from cow_py.contracts.order import Order +from cow_py.contracts.sign import EcdsaSignature, SigningScheme +from cow_py.contracts.sign import sign_order as _sign_order +from cow_py.order_book.api import OrderBookApi +from cow_py.order_book.config import OrderBookAPIConfigFactory +from cow_py.order_book.generated.model import OrderQuoteSide1, TokenAmount +from cow_py.order_book.generated.model import OrderQuoteSideKindSell +from cow_py.order_book.generated.model import ( + UID, + OrderCreation, + OrderQuoteRequest, + OrderQuoteResponse, +) + +BUY_TOKEN = "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14" # WETH +SELL_TOKEN = "0xbe72E441BF55620febc26715db68d3494213D8Cb" # USDC +SELL_AMOUNT_BEFORE_FEE = "10000000000000000000" # 100 USDC with 18 decimals +ORDER_KIND = "sell" +CHAIN = Chain.SEPOLIA +CHAIN_ID = SupportedChainId.SEPOLIA + +config = OrderBookAPIConfigFactory.get_config("prod", CHAIN_ID) +ORDER_BOOK_API = OrderBookApi(config) + +ADDRESS = os.getenv("USER_ADDRESS") +ACCOUNT = Account.from_key(os.getenv("PRIVATE_KEY")) + + +async def get_order_quote( + order_quote_request: OrderQuoteRequest, order_side: OrderQuoteSide1 +) -> OrderQuoteResponse: + return await ORDER_BOOK_API.post_quote(order_quote_request, order_side) + + +def sign_order(order: Order) -> EcdsaSignature: + order_domain = asdict( + domain( + chain=CHAIN, verifying_contract=CowContractAddress.SETTLEMENT_CONTRACT.value + ) + ) + del order_domain["salt"] # TODO: improve interfaces + + return _sign_order(order_domain, order, ACCOUNT, SigningScheme.EIP712) + + +async def post_order(order: Order, signature: EcdsaSignature) -> UID: + order_creation = OrderCreation( + **{ + "from": ADDRESS, + "sellToken": order.sellToken, + "buyToken": order.buyToken, + "sellAmount": order.sellAmount, + "feeAmount": order.feeAmount, + "buyAmount": order.buyAmount, + "validTo": order.validTo, + "kind": order.kind, + "partiallyFillable": order.partiallyFillable, + "appData": order.appData, + "signature": signature.data, + "signingScheme": "eip712", + "receiver": order.receiver, + }, + ) + return await ORDER_BOOK_API.post_order(order_creation) + + +async def main(): + order_quote_request = OrderQuoteRequest( + **{ + "sellToken": SELL_TOKEN, + "buyToken": BUY_TOKEN, + "from": ADDRESS, + } + ) + order_side = OrderQuoteSide1( + kind=OrderQuoteSideKindSell.sell, + sellAmountBeforeFee=TokenAmount(SELL_AMOUNT_BEFORE_FEE), + ) + + order_quote = await get_order_quote(order_quote_request, order_side) + + order_quote_dict = json.loads(order_quote.quote.model_dump_json(by_alias=True)) + order = Order( + **{ + "sellToken": SELL_TOKEN, + "buyToken": BUY_TOKEN, + "receiver": ADDRESS, + "validTo": order_quote_dict["validTo"], + "appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "sellAmount": SELL_AMOUNT_BEFORE_FEE, # Since it is a sell order, the sellAmountBeforeFee is the same as the sellAmount + "buyAmount": order_quote_dict["buyAmount"], + "feeAmount": "0", # CoW Swap does not charge fees + "kind": ORDER_KIND, + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + } + ) + + signature = sign_order(order) + order_uid = await post_order(order, signature) + print(f"order posted on link: {ORDER_BOOK_API.get_order_link(order_uid)}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/poetry.lock b/poetry.lock index dc6e689..990678b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,88 +1,88 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiohttp" -version = "3.9.3" +version = "3.9.4" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, - {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, - {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, - {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, - {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, - {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, - {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, - {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, - {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, - {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, - {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, - {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, + {file = "aiohttp-3.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:76d32588ef7e4a3f3adff1956a0ba96faabbdee58f2407c122dd45aa6e34f372"}, + {file = "aiohttp-3.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:56181093c10dbc6ceb8a29dfeea1e815e1dfdc020169203d87fd8d37616f73f9"}, + {file = "aiohttp-3.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7a5b676d3c65e88b3aca41816bf72831898fcd73f0cbb2680e9d88e819d1e4d"}, + {file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1df528a85fb404899d4207a8d9934cfd6be626e30e5d3a5544a83dbae6d8a7e"}, + {file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f595db1bceabd71c82e92df212dd9525a8a2c6947d39e3c994c4f27d2fe15b11"}, + {file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c0b09d76e5a4caac3d27752027fbd43dc987b95f3748fad2b924a03fe8632ad"}, + {file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:689eb4356649ec9535b3686200b231876fb4cab4aca54e3bece71d37f50c1d13"}, + {file = "aiohttp-3.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3666cf4182efdb44d73602379a66f5fdfd5da0db5e4520f0ac0dcca644a3497"}, + {file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b65b0f8747b013570eea2f75726046fa54fa8e0c5db60f3b98dd5d161052004a"}, + {file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1885d2470955f70dfdd33a02e1749613c5a9c5ab855f6db38e0b9389453dce7"}, + {file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0593822dcdb9483d41f12041ff7c90d4d1033ec0e880bcfaf102919b715f47f1"}, + {file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:47f6eb74e1ecb5e19a78f4a4228aa24df7fbab3b62d4a625d3f41194a08bd54f"}, + {file = "aiohttp-3.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c8b04a3dbd54de6ccb7604242fe3ad67f2f3ca558f2d33fe19d4b08d90701a89"}, + {file = "aiohttp-3.9.4-cp310-cp310-win32.whl", hash = "sha256:8a78dfb198a328bfb38e4308ca8167028920fb747ddcf086ce706fbdd23b2926"}, + {file = "aiohttp-3.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:e78da6b55275987cbc89141a1d8e75f5070e577c482dd48bd9123a76a96f0bbb"}, + {file = "aiohttp-3.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c111b3c69060d2bafc446917534150fd049e7aedd6cbf21ba526a5a97b4402a5"}, + {file = "aiohttp-3.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:efbdd51872cf170093998c87ccdf3cb5993add3559341a8e5708bcb311934c94"}, + {file = "aiohttp-3.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7bfdb41dc6e85d8535b00d73947548a748e9534e8e4fddd2638109ff3fb081df"}, + {file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bd9d334412961125e9f68d5b73c1d0ab9ea3f74a58a475e6b119f5293eee7ba"}, + {file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35d78076736f4a668d57ade00c65d30a8ce28719d8a42471b2a06ccd1a2e3063"}, + {file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:824dff4f9f4d0f59d0fa3577932ee9a20e09edec8a2f813e1d6b9f89ced8293f"}, + {file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52b8b4e06fc15519019e128abedaeb56412b106ab88b3c452188ca47a25c4093"}, + {file = "aiohttp-3.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eae569fb1e7559d4f3919965617bb39f9e753967fae55ce13454bec2d1c54f09"}, + {file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:69b97aa5792428f321f72aeb2f118e56893371f27e0b7d05750bcad06fc42ca1"}, + {file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4d79aad0ad4b980663316f26d9a492e8fab2af77c69c0f33780a56843ad2f89e"}, + {file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:d6577140cd7db19e430661e4b2653680194ea8c22c994bc65b7a19d8ec834403"}, + {file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:9860d455847cd98eb67897f5957b7cd69fbcb436dd3f06099230f16a66e66f79"}, + {file = "aiohttp-3.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:69ff36d3f8f5652994e08bd22f093e11cfd0444cea310f92e01b45a4e46b624e"}, + {file = "aiohttp-3.9.4-cp311-cp311-win32.whl", hash = "sha256:e27d3b5ed2c2013bce66ad67ee57cbf614288bda8cdf426c8d8fe548316f1b5f"}, + {file = "aiohttp-3.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d6a67e26daa686a6fbdb600a9af8619c80a332556245fa8e86c747d226ab1a1e"}, + {file = "aiohttp-3.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c5ff8ff44825736a4065d8544b43b43ee4c6dd1530f3a08e6c0578a813b0aa35"}, + {file = "aiohttp-3.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d12a244627eba4e9dc52cbf924edef905ddd6cafc6513849b4876076a6f38b0e"}, + {file = "aiohttp-3.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dcad56c8d8348e7e468899d2fb3b309b9bc59d94e6db08710555f7436156097f"}, + {file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7e69a7fd4b5ce419238388e55abd220336bd32212c673ceabc57ccf3d05b55"}, + {file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4870cb049f10d7680c239b55428916d84158798eb8f353e74fa2c98980dcc0b"}, + {file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2feaf1b7031ede1bc0880cec4b0776fd347259a723d625357bb4b82f62687b"}, + {file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:939393e8c3f0a5bcd33ef7ace67680c318dc2ae406f15e381c0054dd658397de"}, + {file = "aiohttp-3.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d2334e387b2adcc944680bebcf412743f2caf4eeebd550f67249c1c3696be04"}, + {file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e0198ea897680e480845ec0ffc5a14e8b694e25b3f104f63676d55bf76a82f1a"}, + {file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e40d2cd22914d67c84824045861a5bb0fb46586b15dfe4f046c7495bf08306b2"}, + {file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:aba80e77c227f4234aa34a5ff2b6ff30c5d6a827a91d22ff6b999de9175d71bd"}, + {file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:fb68dc73bc8ac322d2e392a59a9e396c4f35cb6fdbdd749e139d1d6c985f2527"}, + {file = "aiohttp-3.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f3460a92638dce7e47062cf088d6e7663adb135e936cb117be88d5e6c48c9d53"}, + {file = "aiohttp-3.9.4-cp312-cp312-win32.whl", hash = "sha256:32dc814ddbb254f6170bca198fe307920f6c1308a5492f049f7f63554b88ef36"}, + {file = "aiohttp-3.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:63f41a909d182d2b78fe3abef557fcc14da50c7852f70ae3be60e83ff64edba5"}, + {file = "aiohttp-3.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c3770365675f6be220032f6609a8fbad994d6dcf3ef7dbcf295c7ee70884c9af"}, + {file = "aiohttp-3.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:305edae1dea368ce09bcb858cf5a63a064f3bff4767dec6fa60a0cc0e805a1d3"}, + {file = "aiohttp-3.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f121900131d116e4a93b55ab0d12ad72573f967b100e49086e496a9b24523ea"}, + {file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b71e614c1ae35c3d62a293b19eface83d5e4d194e3eb2fabb10059d33e6e8cbf"}, + {file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:419f009fa4cfde4d16a7fc070d64f36d70a8d35a90d71aa27670bba2be4fd039"}, + {file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b39476ee69cfe64061fd77a73bf692c40021f8547cda617a3466530ef63f947"}, + {file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b33f34c9c7decdb2ab99c74be6443942b730b56d9c5ee48fb7df2c86492f293c"}, + {file = "aiohttp-3.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c78700130ce2dcebb1a8103202ae795be2fa8c9351d0dd22338fe3dac74847d9"}, + {file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:268ba22d917655d1259af2d5659072b7dc11b4e1dc2cb9662fdd867d75afc6a4"}, + {file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:17e7c051f53a0d2ebf33013a9cbf020bb4e098c4bc5bce6f7b0c962108d97eab"}, + {file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:7be99f4abb008cb38e144f85f515598f4c2c8932bf11b65add0ff59c9c876d99"}, + {file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:d58a54d6ff08d2547656356eea8572b224e6f9bbc0cf55fa9966bcaac4ddfb10"}, + {file = "aiohttp-3.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7673a76772bda15d0d10d1aa881b7911d0580c980dbd16e59d7ba1422b2d83cd"}, + {file = "aiohttp-3.9.4-cp38-cp38-win32.whl", hash = "sha256:e4370dda04dc8951012f30e1ce7956a0a226ac0714a7b6c389fb2f43f22a250e"}, + {file = "aiohttp-3.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:eb30c4510a691bb87081192a394fb661860e75ca3896c01c6d186febe7c88530"}, + {file = "aiohttp-3.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:84e90494db7df3be5e056f91412f9fa9e611fbe8ce4aaef70647297f5943b276"}, + {file = "aiohttp-3.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7d4845f8501ab28ebfdbeab980a50a273b415cf69e96e4e674d43d86a464df9d"}, + {file = "aiohttp-3.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:69046cd9a2a17245c4ce3c1f1a4ff8c70c7701ef222fce3d1d8435f09042bba1"}, + {file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b73a06bafc8dcc508420db43b4dd5850e41e69de99009d0351c4f3007960019"}, + {file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:418bb0038dfafeac923823c2e63226179976c76f981a2aaad0ad5d51f2229bca"}, + {file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71a8f241456b6c2668374d5d28398f8e8cdae4cce568aaea54e0f39359cd928d"}, + {file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:935c369bf8acc2dc26f6eeb5222768aa7c62917c3554f7215f2ead7386b33748"}, + {file = "aiohttp-3.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74e4e48c8752d14ecfb36d2ebb3d76d614320570e14de0a3aa7a726ff150a03c"}, + {file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:916b0417aeddf2c8c61291238ce25286f391a6acb6f28005dd9ce282bd6311b6"}, + {file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9b6787b6d0b3518b2ee4cbeadd24a507756ee703adbac1ab6dc7c4434b8c572a"}, + {file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:221204dbda5ef350e8db6287937621cf75e85778b296c9c52260b522231940ed"}, + {file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:10afd99b8251022ddf81eaed1d90f5a988e349ee7d779eb429fb07b670751e8c"}, + {file = "aiohttp-3.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2506d9f7a9b91033201be9ffe7d89c6a54150b0578803cce5cb84a943d075bc3"}, + {file = "aiohttp-3.9.4-cp39-cp39-win32.whl", hash = "sha256:e571fdd9efd65e86c6af2f332e0e95dad259bfe6beb5d15b3c3eca3a6eb5d87b"}, + {file = "aiohttp-3.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:7d29dd5319d20aa3b7749719ac9685fbd926f71ac8c77b2477272725f882072d"}, + {file = "aiohttp-3.9.4.tar.gz", hash = "sha256:6ff71ede6d9a5a58cfb7b6fffc83ab5d4a63138276c771ac91ceaaddf5459644"}, ] [package.dependencies] @@ -96,6 +96,17 @@ yarl = ">=1.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns", "brotlicffi"] +[[package]] +name = "aiolimiter" +version = "1.1.0" +description = "asyncio rate limiter, a leaky bucket implementation" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "aiolimiter-1.1.0-py3-none-any.whl", hash = "sha256:0b4997961fc58b8df40279e739f9cf0d3e255e63e9a44f64df567a8c17241e24"}, + {file = "aiolimiter-1.1.0.tar.gz", hash = "sha256:461cf02f82a29347340d031626c92853645c099cb5ff85577b831a7bd21132b5"}, +] + [[package]] name = "aiosignal" version = "1.3.1" @@ -145,13 +156,13 @@ trio = ["trio (>=0.23)"] [[package]] name = "argcomplete" -version = "3.2.2" +version = "3.2.3" description = "Bash tab completion for argparse" optional = false python-versions = ">=3.8" files = [ - {file = "argcomplete-3.2.2-py3-none-any.whl", hash = "sha256:e44f4e7985883ab3e73a103ef0acd27299dbfe2dfed00142c35d4ddd3005901d"}, - {file = "argcomplete-3.2.2.tar.gz", hash = "sha256:f3e49e8ea59b4026ee29548e24488af46e30c9de57d48638e24f54a1ea1000a2"}, + {file = "argcomplete-3.2.3-py3-none-any.whl", hash = "sha256:c12355e0494c76a2a7b73e3a59b09024ca0ba1e279fb9ed6c1b82d5b74b6a70c"}, + {file = "argcomplete-3.2.3.tar.gz", hash = "sha256:bf7900329262e481be5a15f56f19736b376df6f82ed27576fa893652c5de6c23"}, ] [package.extras] @@ -159,13 +170,13 @@ test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] [[package]] name = "ariadne-codegen" -version = "0.12.0" +version = "0.13.0" description = "Generate fully typed GraphQL client from schema, queries and mutations!" optional = false python-versions = "*" files = [ - {file = "ariadne_codegen-0.12.0-py2.py3-none-any.whl", hash = "sha256:bd7faabfa00838ef0ec2b1d87e6623f31cb842f222941290ba091641cff538ed"}, - {file = "ariadne_codegen-0.12.0.tar.gz", hash = "sha256:bc3285543508fb8f286770c90ce63ece2532615628fec2ac7d50420c96e79fd5"}, + {file = "ariadne_codegen-0.13.0-py2.py3-none-any.whl", hash = "sha256:61d0be4b1ba711bc5df35aaf0fa61d04cf4ea6f25a0038b687f845ab4f859a23"}, + {file = "ariadne_codegen-0.13.0.tar.gz", hash = "sha256:52aa67037dcd88a2f6013118e69ba0ed35a49f37312668a1969907f0e9c9bf8b"}, ] [package.dependencies] @@ -233,19 +244,30 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "autoflake" -version = "2.3.0" +version = "2.3.1" description = "Removes unused imports and unused variables" optional = false python-versions = ">=3.8" files = [ - {file = "autoflake-2.3.0-py3-none-any.whl", hash = "sha256:79a51eb8c0744759d2efe052455ab20aa6a314763510c3fd897499a402126327"}, - {file = "autoflake-2.3.0.tar.gz", hash = "sha256:8c2011fa34701b9d7dcf05b9873bc4859d4fce4e62dfea90dffefd1576f5f01d"}, + {file = "autoflake-2.3.1-py3-none-any.whl", hash = "sha256:3ae7495db9084b7b32818b4140e6dc4fc280b712fb414f5b8fe57b0a8e85a840"}, + {file = "autoflake-2.3.1.tar.gz", hash = "sha256:c98b75dc5b0a86459c4f01a1d32ac7eb4338ec4317a4469515ff1e687ecd909e"}, ] [package.dependencies] pyflakes = ">=3.0.0" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} +[[package]] +name = "backoff" +version = "2.2.1" +description = "Function decoration for backoff and retry" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, + {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, +] + [[package]] name = "bitarray" version = "2.9.2" @@ -379,33 +401,33 @@ files = [ [[package]] name = "black" -version = "24.2.0" +version = "24.3.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-24.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6981eae48b3b33399c8757036c7f5d48a535b962a7c2310d19361edeef64ce29"}, - {file = "black-24.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d533d5e3259720fdbc1b37444491b024003e012c5173f7d06825a77508085430"}, - {file = "black-24.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61a0391772490ddfb8a693c067df1ef5227257e72b0e4108482b8d41b5aee13f"}, - {file = "black-24.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:992e451b04667116680cb88f63449267c13e1ad134f30087dec8527242e9862a"}, - {file = "black-24.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:163baf4ef40e6897a2a9b83890e59141cc8c2a98f2dda5080dc15c00ee1e62cd"}, - {file = "black-24.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e37c99f89929af50ffaf912454b3e3b47fd64109659026b678c091a4cd450fb2"}, - {file = "black-24.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9de21bafcba9683853f6c96c2d515e364aee631b178eaa5145fc1c61a3cc92"}, - {file = "black-24.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:9db528bccb9e8e20c08e716b3b09c6bdd64da0dd129b11e160bf082d4642ac23"}, - {file = "black-24.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d84f29eb3ee44859052073b7636533ec995bd0f64e2fb43aeceefc70090e752b"}, - {file = "black-24.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e08fb9a15c914b81dd734ddd7fb10513016e5ce7e6704bdd5e1251ceee51ac9"}, - {file = "black-24.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810d445ae6069ce64030c78ff6127cd9cd178a9ac3361435708b907d8a04c693"}, - {file = "black-24.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ba15742a13de85e9b8f3239c8f807723991fbfae24bad92d34a2b12e81904982"}, - {file = "black-24.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e53a8c630f71db01b28cd9602a1ada68c937cbf2c333e6ed041390d6968faf4"}, - {file = "black-24.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93601c2deb321b4bad8f95df408e3fb3943d85012dddb6121336b8e24a0d1218"}, - {file = "black-24.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0057f800de6acc4407fe75bb147b0c2b5cbb7c3ed110d3e5999cd01184d53b0"}, - {file = "black-24.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:faf2ee02e6612577ba0181f4347bcbcf591eb122f7841ae5ba233d12c39dcb4d"}, - {file = "black-24.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:057c3dc602eaa6fdc451069bd027a1b2635028b575a6c3acfd63193ced20d9c8"}, - {file = "black-24.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08654d0797e65f2423f850fc8e16a0ce50925f9337fb4a4a176a7aa4026e63f8"}, - {file = "black-24.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca610d29415ee1a30a3f30fab7a8f4144e9d34c89a235d81292a1edb2b55f540"}, - {file = "black-24.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:4dd76e9468d5536abd40ffbc7a247f83b2324f0c050556d9c371c2b9a9a95e31"}, - {file = "black-24.2.0-py3-none-any.whl", hash = "sha256:e8a6ae970537e67830776488bca52000eaa37fa63b9988e8c487458d9cd5ace6"}, - {file = "black-24.2.0.tar.gz", hash = "sha256:bce4f25c27c3435e4dace4815bcb2008b87e167e3bf4ee47ccdc5ce906eb4894"}, + {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, + {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, + {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, + {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, + {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, + {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, + {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, + {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, + {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, + {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, + {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, + {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, + {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, + {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, + {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, + {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, + {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, + {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, + {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, + {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, + {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, + {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, ] [package.dependencies] @@ -423,6 +445,17 @@ d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "cached-property" +version = "1.5.2" +description = "A decorator for caching properties in classes." +optional = false +python-versions = "*" +files = [ + {file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"}, + {file = "cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"}, +] + [[package]] name = "certifi" version = "2024.2.2" @@ -544,6 +577,99 @@ files = [ {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] +[[package]] +name = "ckzg" +version = "1.0.0" +description = "Python bindings for C-KZG-4844" +optional = false +python-versions = "*" +files = [ + {file = "ckzg-1.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f40731759b608d74b240fe776853b7b081100d8fc06ac35e22fd0db760b7bcaa"}, + {file = "ckzg-1.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8b5d08189ffda2f869711c4149dc41012f73656bc20606f69b174d15488f6ed1"}, + {file = "ckzg-1.0.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c37af3d01a4b0c3f0a4f51cd0b85df44e30d3686f90c2a7cc84530e4e9d7a00e"}, + {file = "ckzg-1.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1272db9cf5cdd6f564b3de48dae4646d9e04aa10432c0f278ca7c752cf6a333c"}, + {file = "ckzg-1.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5a464900627b66848f4187dd415bea5edf78f3918927bd27461749e75730459"}, + {file = "ckzg-1.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e1d4abc0d58cb04678915ef7c4236834e58774ef692194b9bca15f837a0aaff8"}, + {file = "ckzg-1.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9205a6ea38c5e030f6f719b8f8ea6207423378e0339d45db81c946a0818d0f31"}, + {file = "ckzg-1.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9d8c45cd427f34682add5715360b358ffc2cbd9533372470eae12cbb74960042"}, + {file = "ckzg-1.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:91868e2aa17497ea864bb9408269176d961ba56d89543af292556549b18a03b7"}, + {file = "ckzg-1.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cffc3a23ccc967fd7993a9839aa0c133579bfcfd9f124c1ad8916a21c40ed594"}, + {file = "ckzg-1.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9936e5adf2030fc2747aaadc0cbfee6b5a06507e2b74e70998ac4e37cd7203a6"}, + {file = "ckzg-1.0.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a8d97acb5f84cf2c4db0c962ce3aefa2819b10c5b6b9dccf55e83f2a999676"}, + {file = "ckzg-1.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a49bd5dcf288a40df063f7ebd88476fa96a5d22dcbafc843193964993f36e26"}, + {file = "ckzg-1.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1495b5bb9016160a71d5f2727b935cb532d5578b7d29b280f0531b50c5ef1ee"}, + {file = "ckzg-1.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ad39d0549237d136e32263a71182833e26fab8fe8ab62db4d6161b9a7f74623e"}, + {file = "ckzg-1.0.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d5a838b4de4cc0b01a84531a115cf19aa508049c20256e493a2cca98cf806e3e"}, + {file = "ckzg-1.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dfadf8aab3f5a9a94796ba2b688f3679d1d681afe92dfa223da7d4f751fe487d"}, + {file = "ckzg-1.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:6aff64ce8eae856bb5684c76f8e07d4ac31ff07ad46a24bf62c9ea2104975bc9"}, + {file = "ckzg-1.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7b1eed4e35a3fb35f867770eee12018098bd261fa66b768f75b343e0198ff258"}, + {file = "ckzg-1.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3d7f609e943880303ea3f60b0426c9b53a596c74bb09ceed00c917618b519373"}, + {file = "ckzg-1.0.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f8c422673236ea67608c434956181b050039b2f57b1006503eeec574b1af8467"}, + {file = "ckzg-1.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9321226e65868e66edbe18301b8f76f3298d316e6d3a1261371c7fdbc913816"}, + {file = "ckzg-1.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f6fd5bc8c2362483c61adbd00188f7448c968807f00ee067666355c63cf45e0"}, + {file = "ckzg-1.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:be79e3c4a735f5bf4c71cc07a89500448555f2d4f4f765da5867194c7e46ec5c"}, + {file = "ckzg-1.0.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2896c108425b64f6b741cc389beee2b8467a41f8d4f901f4a4ecc037311dc681"}, + {file = "ckzg-1.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd3f0db4cf514054c386d1a38f9a144725b5109379dd9d2c1b4b0736119f848e"}, + {file = "ckzg-1.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:7a864097cb88be5b7aeff6103bf03d7dfb1c6dda6c8ef82378838ce32e158a15"}, + {file = "ckzg-1.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0404db8ded404b36617d60d678d5671652798952571ae4993d4d379ef6563f4f"}, + {file = "ckzg-1.0.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3aee88b228a9ca81d677d57d8d3f6ee483165d8b3955ea408bda674d0f9b4ee5"}, + {file = "ckzg-1.0.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6b4d15188803602afc56e113fc588617219a6316789766fc95e0fa010a93ab"}, + {file = "ckzg-1.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ae6d24e83af8c097b62fdc2183378b9f2d8253fa14ccfc07d075a579f98d876"}, + {file = "ckzg-1.0.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8facda4eafc451bb5f6019a2b779f1b6da7f91322aef0eab1f1d9f542220de1c"}, + {file = "ckzg-1.0.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:4f552fa3b654bc376fcb73e975d521eacff324dba111fa2f0c80c84ad586a0b1"}, + {file = "ckzg-1.0.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:851b7eaca0034b51b6867623b0fae2260466126d8fc669646890464812afd932"}, + {file = "ckzg-1.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:df63d78d9a3d1ffcf32ccb262512c780de42798543affc1209f6fd0cddac49b4"}, + {file = "ckzg-1.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3aefd29f6d339358904ed88e5a642e5bf338fd85151a982a040d4352ae95e53f"}, + {file = "ckzg-1.0.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f2bbbcd24f5ac7f29a0f3f3f51d8934764f5d579e63601a415ace4dad0c2785"}, + {file = "ckzg-1.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ed54765a3067f20786a0c6ee24a8440cfedfe39c5865744c99f605e6ec4249"}, + {file = "ckzg-1.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5101500009a8851843b5aab44bc320b281cfe46ffbbab35f29fa763dc2ac4a2"}, + {file = "ckzg-1.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a35e0f027749a131a5086dcb3f094ec424280cdf7708c24e0c45421a0e9bebf"}, + {file = "ckzg-1.0.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:71860eda6019cc57b197037427ad4078466de232a768fa7c77c7094585689a8d"}, + {file = "ckzg-1.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87729a2e861093d9ee4667dcf047a0073644da7f9de5b9c269821e3c9c3f7164"}, + {file = "ckzg-1.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1d1bd47cfa82f92f14ec77fffee6480b03144f414861fc6664190e89d3aa542d"}, + {file = "ckzg-1.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4644e6e0d66d4a36dc37c2ef64807d1db39bf76b10a933b2f7fbb0b4ee9d991"}, + {file = "ckzg-1.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:96d88c6ea2fd49ecfa16767d05a2d056f1bd1a42b0cf10ab99fb4f88fefab5d7"}, + {file = "ckzg-1.0.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c921b9172aa155ede173abe9d3495c04a55b1afde317339443451e889b531891"}, + {file = "ckzg-1.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a09cce801a20929d49337bd0f1df6d079d5a2ebaa58f58ab8649c706485c759"}, + {file = "ckzg-1.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a02d21ceda0c3bec82342f050de5b22eb4a928be00913fa8992ab0f717095f8"}, + {file = "ckzg-1.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bf751e989a428be569e27010c98192451af4c729d5c27a6e0132647fe93b6e84"}, + {file = "ckzg-1.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37192e9fcbced22e64cd00785ea082bd22254ce7d9cfdfd5364683bea8e1d043"}, + {file = "ckzg-1.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:54808ba5b3692ff31713de6d57c30c21060f11916d2e233f5554fcc85790fcda"}, + {file = "ckzg-1.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:d3b343a4a26d5994bdb39216f5b03bf2345bb6e37ae90fcf7181df37c244217a"}, + {file = "ckzg-1.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:481dfd101acc8a473146b35e61c11cee2ef41210b77775f306c4f1f7f8bdbf28"}, + {file = "ckzg-1.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bd392f3ae05a851f9aa1fc114b565cb7e6744cec39790af56af2adf9dd400f3d"}, + {file = "ckzg-1.0.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2ca50b9d0e947d3b5530dacf25cc00391d041e861751c4872eba4a4567a2efe"}, + {file = "ckzg-1.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91dafec4f72e30176fb9861d0e2ed46cd506f6837ed70066f2136378f5cd84df"}, + {file = "ckzg-1.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c72b07d5cac293d7e49a5510d56163f18cdbf9c7a6c6446422964d5667097c2"}, + {file = "ckzg-1.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:67144d1b545cdd6cb5af38ed2c03b234a24f72b6021ea095b70f0cfe11181bd6"}, + {file = "ckzg-1.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43935d730a9ee13ca264455356bdd01055c55c241508f5682d67265379b29dcf"}, + {file = "ckzg-1.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5911419a785c732f0f5edcda89ecc489e7880191b8c0147f629025cb910f913"}, + {file = "ckzg-1.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a00c295c5657162c24b162ca9a030fbfbc6930e0782378ce3e3d64b14cf470e"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8d272107d63500ba9c62adef39f01835390ee467c2583fd96c78f05773d87b0d"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:52bfcad99cc0f5611c3a7e452de4d7fa66ce020327c1c1de425b84b20794687b"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ae70915d41702d33775d9b81c106b2bff5aa7981f82b06e0c5892daa921ff55"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5deaae9151215d1fad3934fa423a87ee752345f665448a30f58bf5c3177c4623"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f7e8861174fe26e6bb0f13655aa1f07fd7c3300852748b0f6e47b998153b56b"}, + {file = "ckzg-1.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dc6c211e16ef7750b2579346eaa05e4f1e7f1726effa55c2cb42354603800b01"}, + {file = "ckzg-1.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d392ef8281f306a0377f4e5fe816e03e4dce2754a4b2ab209b16d9628b7a0bac"}, + {file = "ckzg-1.0.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52cbe279f5d3ec9dd7745de8e796383ba201302606edaa9838b5dd5a34218241"}, + {file = "ckzg-1.0.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a5d3367cee7ebb48131acc78ca3fb0565e3af3fd8fa8eb4ca25bb88577692c4"}, + {file = "ckzg-1.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55e8c6d8df9dc1bdd3862114e239c292f9bdd92d67055ca4e0e7503826e6524f"}, + {file = "ckzg-1.0.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b040396df453b51cd5f1461bec9b942173b95ca181c7f65caa10c0204cb6144a"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7951c53321136aabdab64dc389c92ffeda5859d59304b97092e893a6b09e9722"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:56256067d31eb6eed1a42c9f3038936aeb7decee322aa13a3224b51cfa3e8026"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c166f254ce3434dd0d56ef64788fc9637d60721f4e7e126b15a847abb9a44962"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab02c7ad64fb8616a430b05ad2f8fa4f3fc0a22e3dd4ea7a5d5fa4362534bb21"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63bb5e6bc4822c732270c70ef12522b0215775ff61cae04fb54983973aef32e3"}, + {file = "ckzg-1.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:409f1f18dbc92df5ddbf1ff0d154dc2280a495ec929a4fa27abc69eeacf31ff0"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2eceae0ef7189d47bd89fd9efd9d8f54c5b06bc92c435ec00c62815363cd9d79"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e189c00a0030d1a593b020264d7f9b30fa0b980d108923f353c565c206a99147"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36735543ce3aec4730e7128690265ef90781d28e9b56c039c72b6b2ce9b06839"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fef5f276e24f4bdd19e28ddcc5212e9b6c8514d3c7426bd443c9221f348c176f"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d02164a0d84e55965c14132f6d43cc367be3d12eb318f79ba2f262dac47665c2"}, + {file = "ckzg-1.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:88fafab3493a12d5212374889783352bb4b59dddc9e61c86d063358eff6da7bb"}, +] + [[package]] name = "click" version = "8.1.7" @@ -569,6 +695,73 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "coverage" +version = "7.4.4" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, + {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, + {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, + {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, + {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, + {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, + {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, + {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, + {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, + {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, + {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, + {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, + {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + [[package]] name = "cytoolz" version = "0.12.3" @@ -690,13 +883,13 @@ cython = ["cython"] [[package]] name = "datamodel-code-generator" -version = "0.25.4" +version = "0.25.5" description = "Datamodel Code Generator" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "datamodel_code_generator-0.25.4-py3-none-any.whl", hash = "sha256:cbf179517c610dce81589203d72b52e6ab848d78cb57264c1e5d929a9cc9d9a4"}, - {file = "datamodel_code_generator-0.25.4.tar.gz", hash = "sha256:8e64c94a3bc92c69a6f56de84f0d61f70fd65c2e0ac95a27ce66837bd04c5492"}, + {file = "datamodel_code_generator-0.25.5-py3-none-any.whl", hash = "sha256:3b62b42c8ebf2bb98cfbc24467b523c5b76780c585b72f4ac2fc1f1f576702ab"}, + {file = "datamodel_code_generator-0.25.5.tar.gz", hash = "sha256:545f897481a94781e32b3c26a452ce049320b091310729f7fc6fa780f6a87898"}, ] [package.dependencies] @@ -710,7 +903,6 @@ packaging = "*" pydantic = [ {version = ">=1.10.0,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.12\" and python_version < \"4.0\""}, {version = ">=1.10.0,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, - {version = ">=1.5.1,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version < \"3.10\""}, {version = ">=1.9.0,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] pyyaml = ">=6.0.1" @@ -781,39 +973,40 @@ idna = ">=2.0.0" [[package]] name = "eth-abi" -version = "5.0.0" +version = "5.1.0" description = "eth_abi: Python utilities for working with Ethereum ABI definitions, especially encoding and decoding" optional = false -python-versions = ">=3.8, <4" +python-versions = "<4,>=3.8" files = [ - {file = "eth_abi-5.0.0-py3-none-any.whl", hash = "sha256:936a715d7366ac13cac665cbdaf01cc4aabbe8c2d810d716287a9634f9665e01"}, - {file = "eth_abi-5.0.0.tar.gz", hash = "sha256:89c4454d794d9ed92ad5cb2794698c5cee6b7b3ca6009187d0e282adc7f9b6dc"}, + {file = "eth_abi-5.1.0-py3-none-any.whl", hash = "sha256:84cac2626a7db8b7d9ebe62b0fdca676ab1014cc7f777189e3c0cd721a4c16d8"}, + {file = "eth_abi-5.1.0.tar.gz", hash = "sha256:33ddd756206e90f7ddff1330cc8cac4aa411a824fe779314a0a52abea2c8fc14"}, ] [package.dependencies] eth-typing = ">=3.0.0" eth-utils = ">=2.0.0" -parsimonious = ">=0.9.0,<0.10.0" +parsimonious = ">=0.10.0,<0.11.0" [package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-timeout (>=2.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-xdist (>=2.4.0)"] +test = ["eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-timeout (>=2.0.0)", "pytest-xdist (>=2.4.0)"] tools = ["hypothesis (>=4.18.2,<5.0.0)"] [[package]] name = "eth-account" -version = "0.11.0" +version = "0.11.2" description = "eth-account: Sign Ethereum transactions and messages with local private keys" optional = false -python-versions = ">=3.8, <4" +python-versions = "<4,>=3.8" files = [ - {file = "eth-account-0.11.0.tar.gz", hash = "sha256:2ffc7a0c7538053a06a7d11495c16c7ad9897dd42be0f64ca7551e9f6e0738c3"}, - {file = "eth_account-0.11.0-py3-none-any.whl", hash = "sha256:76dd261ea096ee09e51455b0a4c99f22185516fdc062f63df0817c28f605e430"}, + {file = "eth-account-0.11.2.tar.gz", hash = "sha256:b43daf2c0ae43f2a24ba754d66889f043fae4d3511559cb26eb0122bae9afbbd"}, + {file = "eth_account-0.11.2-py3-none-any.whl", hash = "sha256:95157c262a9823c1e08be826d4bc304bf32f0c32e80afb38c126a325a64f651a"}, ] [package.dependencies] bitarray = ">=2.4.0" +ckzg = ">=0.4.3" eth-abi = ">=4.0.0-b.2" eth-keyfile = ">=0.6.0" eth-keys = ">=0.4.0" @@ -827,19 +1020,39 @@ dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "coverage", "hypothesis (>=4. docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] test = ["coverage", "hypothesis (>=4.18.0,<5)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +[[package]] +name = "eth-bloom" +version = "3.0.0" +description = "A python implementation of the bloom filter used by Ethereum" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth-bloom-3.0.0.tar.gz", hash = "sha256:94bab384b01f2eb1012abbd6bb504e4c743878414d8695ee5a5d25f4247b3886"}, + {file = "eth_bloom-3.0.0-py3-none-any.whl", hash = "sha256:bb884ece93d292dfbbe4696744db874a88ac5bfc45f6f1b0ee147d801604a46c"}, +] + +[package.dependencies] +eth-hash = {version = ">=0.4.0", extras = ["pycryptodome"]} + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "hypothesis (>=3.31.2)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["towncrier (>=21,<22)"] +test = ["hypothesis (>=3.31.2)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + [[package]] name = "eth-hash" -version = "0.6.0" +version = "0.7.0" description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" optional = false python-versions = ">=3.8, <4" files = [ - {file = "eth-hash-0.6.0.tar.gz", hash = "sha256:ae72889e60db6acbb3872c288cfa02ed157f4c27630fcd7f9c8442302c31e478"}, - {file = "eth_hash-0.6.0-py3-none-any.whl", hash = "sha256:9f8daaa345764f8871dc461855049ac54ae4291d780279bce6fce7f24e3f17d3"}, + {file = "eth-hash-0.7.0.tar.gz", hash = "sha256:bacdc705bfd85dadd055ecd35fd1b4f846b671add101427e089a4ca2e8db310a"}, + {file = "eth_hash-0.7.0-py3-none-any.whl", hash = "sha256:b8d5a230a2b251f4a291e3164a23a14057c4a6de4b0aa4a16fa4dc9161b57e2f"}, ] [package.dependencies] pycryptodome = {version = ">=3.6.6,<4", optional = true, markers = "extra == \"pycryptodome\""} +safe-pysha3 = {version = ">=1.0.0", optional = true, markers = "python_version >= \"3.9\" and extra == \"pysha3\""} [package.extras] dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] @@ -850,13 +1063,13 @@ test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-keyfile" -version = "0.7.0" +version = "0.8.0" description = "eth-keyfile: A library for handling the encrypted keyfiles used to store ethereum private keys" optional = false python-versions = ">=3.8, <4" files = [ - {file = "eth-keyfile-0.7.0.tar.gz", hash = "sha256:6bdb8110c3a50439deb68a04c93c9d5ddd5402353bfae1bf4cfca1d6dff14fcf"}, - {file = "eth_keyfile-0.7.0-py3-none-any.whl", hash = "sha256:6a89b231a2fe250c3a8f924f2695bb9cce33ddd0d6f7ebbcdacd183d7f83d537"}, + {file = "eth-keyfile-0.8.0.tar.gz", hash = "sha256:02e3c2e564c7403b92db3fef8ecae3d21123b15787daecd5b643a57369c530f9"}, + {file = "eth_keyfile-0.8.0-py3-none-any.whl", hash = "sha256:9e09f5bc97c8309876c06bdea7a94f0051c25ba3109b5df37afb815418322efe"}, ] [package.dependencies] @@ -912,15 +1125,46 @@ dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "ip docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] test = ["eth-hash[pycryptodome]", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +[[package]] +name = "eth-tester" +version = "0.11.0b1" +description = "eth-tester: Tools for testing Ethereum applications." +optional = false +python-versions = "<4,>=3.8" +files = [ + {file = "eth-tester-0.11.0b1.tar.gz", hash = "sha256:8f9985037bbe6057cfff705063add5de506d75b725740bc44fb5ac03cc7b5130"}, + {file = "eth_tester-0.11.0b1-py3-none-any.whl", hash = "sha256:5ac85ff048ce2a5415aa5624d99093ad8b7d1f1f80e23b6d220ca5432839fb00"}, +] + +[package.dependencies] +eth-abi = ">=3.0.1" +eth-account = ">=0.11.2" +eth-hash = [ + {version = ">=0.1.4,<1.0.0", extras = ["pysha3"], optional = true, markers = "implementation_name == \"cpython\" and extra == \"py-evm\""}, + {version = ">=0.1.4,<1.0.0", extras = ["pycryptodome"], optional = true, markers = "implementation_name == \"pypy\" and extra == \"py-evm\""}, +] +eth-keys = ">=0.4.0" +eth-utils = ">=2.0.0" +py-evm = {version = ">=0.10.0b0,<0.11.0b0", optional = true, markers = "extra == \"py-evm\""} +rlp = ">=3.0.0" +semantic-version = ">=2.6.0" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome] (>=0.1.4,<1.0.0)", "eth-hash[pycryptodome] (>=0.1.4,<1.0.0)", "eth-hash[pysha3] (>=0.1.4,<1.0.0)", "ipython", "pre-commit (>=3.4.0)", "py-evm (>=0.10.0b0,<0.11.0b0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.0.0,<3)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["towncrier (>=21,<22)"] +py-evm = ["eth-hash[pycryptodome] (>=0.1.4,<1.0.0)", "eth-hash[pysha3] (>=0.1.4,<1.0.0)", "py-evm (>=0.10.0b0,<0.11.0b0)"] +pyevm = ["eth-hash[pycryptodome] (>=0.1.4,<1.0.0)", "eth-hash[pysha3] (>=0.1.4,<1.0.0)", "py-evm (>=0.10.0b0,<0.11.0b0)"] +test = ["eth-hash[pycryptodome] (>=0.1.4,<1.0.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.0.0,<3)"] + [[package]] name = "eth-typing" -version = "4.0.0" +version = "4.1.0" description = "eth-typing: Common type annotations for ethereum python packages" optional = false -python-versions = ">=3.8, <4" +python-versions = "<4,>=3.8" files = [ - {file = "eth-typing-4.0.0.tar.gz", hash = "sha256:9af0b6beafbc5c2e18daf19da5f5a68315023172c4e79d149e12ad10a3d3f731"}, - {file = "eth_typing-4.0.0-py3-none-any.whl", hash = "sha256:7e556bea322b6e8c0a231547b736c258e10ce9eed5ddc254f51031b12af66a16"}, + {file = "eth-typing-4.1.0.tar.gz", hash = "sha256:ed52b0c6b049240fd810bc87c8857c7ea39370f060f70b9ca3876285269f2938"}, + {file = "eth_typing-4.1.0-py3-none-any.whl", hash = "sha256:1f1b16bf37bfe0be730731fd24c7398e931a2b45a8feebf82df2e77a611a23be"}, ] [package.extras] @@ -930,13 +1174,13 @@ test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-utils" -version = "4.0.0" +version = "4.1.0" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" optional = false -python-versions = ">=3.8, <4" +python-versions = "<4,>=3.8" files = [ - {file = "eth-utils-4.0.0.tar.gz", hash = "sha256:58f9c57900e0f430be728a5e976dc6ed51f493a61e8a4ff1f73c043832cd4f2f"}, - {file = "eth_utils-4.0.0-py3-none-any.whl", hash = "sha256:38d0a5a4b5bb8f2e583f040ede678c47d9eae57a058a11895271a947853947a0"}, + {file = "eth-utils-4.1.0.tar.gz", hash = "sha256:c170168198ddecac1ea911f74937e9364de81dbd03f42450fe40725c4d6e6220"}, + {file = "eth_utils-4.1.0-py3-none-any.whl", hash = "sha256:f2e0f617edc81e53fad0faca7f7b169e56bef59ecc530d919a7482640236a228"}, ] [package.dependencies] @@ -980,18 +1224,18 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "filelock" -version = "3.13.1" +version = "3.13.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "filelock-3.13.4-py3-none-any.whl", hash = "sha256:404e5e9253aa60ad457cae1be07c0f0ca90a63931200a47d9b6a6af84fd7b45f"}, + {file = "filelock-3.13.4.tar.gz", hash = "sha256:d13f466618bfde72bd2c18255e269f72542c6e70e7bac83a0232d6b1cc5c8cf4"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] [[package]] @@ -1131,13 +1375,13 @@ test = ["eth-utils (>=1.0.1,<3)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>= [[package]] name = "httpcore" -version = "1.0.4" +version = "1.0.5" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.4-py3-none-any.whl", hash = "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73"}, - {file = "httpcore-1.0.4.tar.gz", hash = "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022"}, + {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, + {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, ] [package.dependencies] @@ -1148,7 +1392,7 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.25.0)"] +trio = ["trio (>=0.22.0,<0.26.0)"] [[package]] name = "httpx" @@ -1190,13 +1434,13 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -1227,13 +1471,13 @@ files = [ [[package]] name = "ipython" -version = "8.18.1" +version = "8.23.0" description = "IPython: Productive Interactive Computing" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"}, - {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"}, + {file = "ipython-8.23.0-py3-none-any.whl", hash = "sha256:07232af52a5ba146dc3372c7bf52a0f890a23edf38d77caef8d53f9cdc2584c1"}, + {file = "ipython-8.23.0.tar.gz", hash = "sha256:7468edaf4f6de3e1b912e57f66c241e6fd3c7099f2ec2136e239e142e800274d"}, ] [package.dependencies] @@ -1242,25 +1486,26 @@ decorator = "*" exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" -pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" -traitlets = ">=5" -typing-extensions = {version = "*", markers = "python_version < \"3.10\""} +traitlets = ">=5.13.0" +typing-extensions = {version = "*", markers = "python_version < \"3.12\""} [package.extras] -all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "stack-data", "typing-extensions"] kernel = ["ipykernel"] +matplotlib = ["matplotlib"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"] +test = ["pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] [[package]] name = "isort" @@ -1347,6 +1592,46 @@ files = [ [package.dependencies] referencing = ">=0.31.0" +[[package]] +name = "libcst" +version = "1.3.1" +description = "A concrete syntax tree with AST-like properties for Python 3.0 through 3.12 programs." +optional = false +python-versions = ">=3.9" +files = [ + {file = "libcst-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:de93193cba6d54f2a4419e94ba2de642b111f52e4fa01bb6e2c655914585f65b"}, + {file = "libcst-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2d64d86dcd6c80a5dac2e243c5ed7a7a193242209ac33bad4b0639b24f6d131"}, + {file = "libcst-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db084f7bbf825c7bd5ed256290066d0336df6a7dc3a029c9870a64cd2298b87f"}, + {file = "libcst-1.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16880711be03a1f5da7028fe791ba5b482a50d830225a70272dc332dfd927652"}, + {file = "libcst-1.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:189bb28c19c5dd3c64583f969b72f7732dbdb1dee9eca3acc85099e4cef9148b"}, + {file = "libcst-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:181372386c986e3de07d7a93f269214cd825adc714f1f9da8252b44f05e181c4"}, + {file = "libcst-1.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c2020f7449270e3ff0bdc481ae244d812f2d9a8b7dbff0ea66b830f4b350f54"}, + {file = "libcst-1.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:be3bf9aaafebda6a21e241e819f0ab67e186e898c3562704e41241cf8738353a"}, + {file = "libcst-1.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a0d250fb6a2c1d158f30d25ba5e33e3ed3672d2700d480dd47beffd1431a008"}, + {file = "libcst-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ad5741b251d901f3da1819ac539192230cc6f8f81aaf04eb4ec0009c1c97285"}, + {file = "libcst-1.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b740dc0c3d1adbd91442fb878343d5a11e23a0e3ac5484be301fd8d148bcb085"}, + {file = "libcst-1.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:9e6bc95fa7dde79cde63a34a0412cd4a3d9fcc27be781a590f8c45c840c83658"}, + {file = "libcst-1.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4186076ce12141609ce950d61867b2a73ea199a7a9870dbafa76ad600e075b3c"}, + {file = "libcst-1.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ed52a1a2fe4d8603de51649db5e438317b8116ebb9fc09ec68703535fe6c1c8"}, + {file = "libcst-1.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0886a9963597367b227345f19b24931b3ed6a4703fff237760745f90f0e6a20"}, + {file = "libcst-1.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:904c4cc5c801a5747e64b43e0accc87c67a4c804842d977ee215872c4cf8cf88"}, + {file = "libcst-1.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cdb7e8a118b60e064a02f6cbfa4d328212a3a115d125244495190f405709d5f"}, + {file = "libcst-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:431badf0e544b79c0ac9682dbd291ff63ddbc3c3aca0d13d3cc7a10c3a9db8a2"}, + {file = "libcst-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:701f5335e4fd566871497b9af1e871c98e1ef10c30b3b244f39343d709213401"}, + {file = "libcst-1.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7c6e709623b68ca9148e8ecbdc145f7b83befb26032e4bf6a8122500ba558b17"}, + {file = "libcst-1.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ede0f026a82b03b33a559ec566860085ece2e76d8f9bc21cb053eedf9cde8c79"}, + {file = "libcst-1.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c12b7b01d8745f82dd86a82acd2a9f8e8e7d6c94ddcfda996896e83d1a8d5c42"}, + {file = "libcst-1.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2995ca687118a9d3d41876f7270bc29305a2d402f4b8c81a3cff0aeee6d4c81"}, + {file = "libcst-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:2dbac1ac0a9d59ea7bbc3f87cdcca5bfe98835e31c668e95cb6f3d907ffc53fc"}, + {file = "libcst-1.3.1.tar.gz", hash = "sha256:03b1df1ae02456f1d465fcd5ead1d0d454bb483caefd8c8e6bde515ffdb53d1b"}, +] + +[package.dependencies] +pyyaml = ">=5.2" + +[package.extras] +dev = ["Sphinx (>=5.1.1)", "black (==23.12.1)", "build (>=0.10.0)", "coverage (>=4.5.4)", "fixit (==2.1.0)", "flake8 (==7.0.0)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.1.3)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<1.5)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.18)", "setuptools-rust (>=1.5.2)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.5.1)", "usort (==1.0.8.post1)"] + [[package]] name = "lru-dict" version = "1.2.0" @@ -1441,6 +1726,30 @@ files = [ [package.extras] test = ["pytest"] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + [[package]] name = "markupsafe" version = "2.1.5" @@ -1524,6 +1833,17 @@ files = [ [package.dependencies] traitlets = "*" +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + [[package]] name = "multidict" version = "6.0.5" @@ -1650,23 +1970,24 @@ setuptools = "*" [[package]] name = "packaging" -version = "23.2" +version = "24.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] name = "parsimonious" -version = "0.9.0" +version = "0.10.0" description = "(Soon to be) the fastest pure-Python PEG parser I could muster" optional = false python-versions = "*" files = [ - {file = "parsimonious-0.9.0.tar.gz", hash = "sha256:b2ad1ae63a2f65bd78f5e0a8ac510a98f3607a43f1db2a8d46636a5d9e4a30c1"}, + {file = "parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f"}, + {file = "parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c"}, ] [package.dependencies] @@ -1674,18 +1995,18 @@ regex = ">=2022.3.15" [[package]] name = "parso" -version = "0.8.3" +version = "0.8.4" description = "A Python Parser" optional = false python-versions = ">=3.6" files = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, ] [package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] [[package]] name = "pathspec" @@ -1744,13 +2065,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.6.2" +version = "3.7.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-3.6.2-py2.py3-none-any.whl", hash = "sha256:ba637c2d7a670c10daedc059f5c49b5bd0aadbccfcd7ec15592cf9665117532c"}, - {file = "pre_commit-3.6.2.tar.gz", hash = "sha256:c3ef34f463045c88658c5b99f38c1e297abdcc0ff13f98d3370055fbbfabc67e"}, + {file = "pre_commit-3.7.0-py2.py3-none-any.whl", hash = "sha256:5eae9e10c2b5ac51577c3452ec0a490455c45a0533f7960f993a0d01e59decab"}, + {file = "pre_commit-3.7.0.tar.gz", hash = "sha256:e209d61b8acdcf742404408531f0c37d49d2c734fd7cff2d6076083d191cb060"}, ] [package.dependencies] @@ -1776,22 +2097,22 @@ wcwidth = "*" [[package]] name = "protobuf" -version = "4.25.3" +version = "5.26.1" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, - {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, - {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, - {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, - {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, - {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, - {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, - {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, - {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, - {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, - {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, + {file = "protobuf-5.26.1-cp310-abi3-win32.whl", hash = "sha256:3c388ea6ddfe735f8cf69e3f7dc7611e73107b60bdfcf5d0f024c3ccd3794e23"}, + {file = "protobuf-5.26.1-cp310-abi3-win_amd64.whl", hash = "sha256:e6039957449cb918f331d32ffafa8eb9255769c96aa0560d9a5bf0b4e00a2a33"}, + {file = "protobuf-5.26.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:38aa5f535721d5bb99861166c445c4105c4e285c765fbb2ac10f116e32dcd46d"}, + {file = "protobuf-5.26.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fbfe61e7ee8c1860855696e3ac6cfd1b01af5498facc6834fcc345c9684fb2ca"}, + {file = "protobuf-5.26.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:f7417703f841167e5a27d48be13389d52ad705ec09eade63dfc3180a959215d7"}, + {file = "protobuf-5.26.1-cp38-cp38-win32.whl", hash = "sha256:d693d2504ca96750d92d9de8a103102dd648fda04540495535f0fec7577ed8fc"}, + {file = "protobuf-5.26.1-cp38-cp38-win_amd64.whl", hash = "sha256:9b557c317ebe6836835ec4ef74ec3e994ad0894ea424314ad3552bc6e8835b4e"}, + {file = "protobuf-5.26.1-cp39-cp39-win32.whl", hash = "sha256:b9ba3ca83c2e31219ffbeb9d76b63aad35a3eb1544170c55336993d7a18ae72c"}, + {file = "protobuf-5.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ee014c2c87582e101d6b54260af03b6596728505c79f17c8586e7523aaa8f8c"}, + {file = "protobuf-5.26.1-py3-none-any.whl", hash = "sha256:da612f2720c0183417194eeaa2523215c4fcc1a1949772dc65f05047e08d5932"}, + {file = "protobuf-5.26.1.tar.gz", hash = "sha256:8ca2a1d97c290ec7b16e4e5dff2e5ae150cc1582f55b5ab300d45cb0dfa90e51"}, ] [[package]] @@ -1819,6 +2140,76 @@ files = [ [package.extras] tests = ["pytest"] +[[package]] +name = "py-ecc" +version = "7.0.0" +description = "py-ecc: Elliptic curve crypto in python including secp256k1, alt_bn128, and bls12_381" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "py-ecc-7.0.0.tar.gz", hash = "sha256:c141e7330559758d2233adaf0af1f05ec4cade67e7fa35fc118750ce79d83257"}, + {file = "py_ecc-7.0.0-py3-none-any.whl", hash = "sha256:a655fa499ab2e695c9d4e49be19e40ad195dd61076642edcbcbb5b7c645820cf"}, +] + +[package.dependencies] +cached-property = ">=1.5.1" +eth-typing = ">=3.0.0" +eth-utils = ">=2.0.0" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "py-evm" +version = "0.10.0b6" +description = "Python implementation of the Ethereum Virtual Machine" +optional = false +python-versions = "<4,>=3.8" +files = [ + {file = "py_evm-0.10.0b6-py3-none-any.whl", hash = "sha256:98d886d7d50937924cfb3d6607c9ec7259c91b082ce4972a569a89b363d7be32"}, +] + +[package.dependencies] +cached-property = ">=1.5.1" +ckzg = ">=0.4.3" +eth-bloom = ">=1.0.3" +eth-keys = ">=0.4.0" +eth-typing = ">=3.3.0" +eth-utils = ">=2.0.0" +lru-dict = ">=1.1.6" +py-ecc = ">=1.4.7" +rlp = ">=3.0.0" +trie = ">=2.0.0" + +[package.extras] +benchmark = ["termcolor (>=1.1.0)", "web3 (>=6.0.0)"] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "cached-property (>=1.5.1)", "ckzg (>=0.4.3)", "eth-bloom (>=1.0.3)", "eth-keys (>=0.4.0)", "eth-typing (>=3.3.0)", "eth-utils (>=2.0.0)", "factory-boy (>=3.0.0)", "hypothesis (>=5,<6)", "ipython", "lru-dict (>=1.1.6)", "pre-commit (>=3.4.0)", "py-ecc (>=1.4.7)", "py-evm (>=0.8.0b1)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.20.0)", "pytest-cov (>=4.0.0)", "pytest-timeout (>=2.0.0)", "pytest-xdist (>=3.0)", "rlp (>=3.0.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "sphinxcontrib-asyncio (>=0.2.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "trie (>=2.0.0)", "twine", "wheel"] +docs = ["py-evm (>=0.8.0b1)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "sphinxcontrib-asyncio (>=0.2.0)", "towncrier (>=21,<22)"] +eth = ["cached-property (>=1.5.1)", "ckzg (>=0.4.3)", "eth-bloom (>=1.0.3)", "eth-keys (>=0.4.0)", "eth-typing (>=3.3.0)", "eth-utils (>=2.0.0)", "lru-dict (>=1.1.6)", "py-ecc (>=1.4.7)", "rlp (>=3.0.0)", "trie (>=2.0.0)"] +eth-extra = ["blake2b-py (>=0.2.0)", "coincurve (>=18.0.0)"] +test = ["factory-boy (>=3.0.0)", "hypothesis (>=5,<6)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.20.0)", "pytest-cov (>=4.0.0)", "pytest-timeout (>=2.0.0)", "pytest-xdist (>=3.0)"] + +[[package]] +name = "py-geth" +version = "4.4.0" +description = "py-geth: Run Go-Ethereum as a subprocess" +optional = false +python-versions = "<4,>=3.8" +files = [ + {file = "py-geth-4.4.0.tar.gz", hash = "sha256:c08d84f6dad4f86a9b8ffd74c0a0f160d600db0ee45dfc2a66d5e13522aeb039"}, + {file = "py_geth-4.4.0-py3-none-any.whl", hash = "sha256:ae8771b028c68f6710e6434d2aa1310ce2ba3cc9099d244d9bb5a9e340786a92"}, +] + +[package.dependencies] +semantic-version = ">=2.6.0" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "flaky (>=3.2.0)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "requests (>=2.20)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["towncrier (>=21,<22)"] +test = ["flaky (>=3.2.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + [[package]] name = "pybars3" version = "0.9.7" @@ -1832,6 +2223,24 @@ files = [ [package.dependencies] PyMeta3 = ">=0.5.1" +[[package]] +name = "pycln" +version = "2.4.0" +description = "A formatter for finding and removing unused import statements." +optional = false +python-versions = ">=3.7.0,<4" +files = [ + {file = "pycln-2.4.0-py3-none-any.whl", hash = "sha256:d1bf648df17077306100815d255d45430035b36f66bac635df04a323c61ba126"}, + {file = "pycln-2.4.0.tar.gz", hash = "sha256:1f3eefb7be18a9ee06c3bdd0ba2e91218cd39317e20130325f107e96eb84b9f6"}, +] + +[package.dependencies] +libcst = ">=0.3.10" +pathspec = ">=0.9.0" +pyyaml = ">=5.3.1" +tomlkit = ">=0.11.1" +typer = ">=0.4.1" + [[package]] name = "pycryptodome" version = "3.20.0" @@ -1875,19 +2284,19 @@ files = [ [[package]] name = "pydantic" -version = "2.6.2" +version = "2.7.0" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.2-py3-none-any.whl", hash = "sha256:37a5432e54b12fecaa1049c5195f3d860a10e01bdfd24f1840ef14bd0d3aeab3"}, - {file = "pydantic-2.6.2.tar.gz", hash = "sha256:a09be1c3d28f3abe37f8a78af58284b236a92ce520105ddc91a6d29ea1176ba7"}, + {file = "pydantic-2.7.0-py3-none-any.whl", hash = "sha256:9dee74a271705f14f9a1567671d144a851c675b072736f0a7b2608fd9e495352"}, + {file = "pydantic-2.7.0.tar.gz", hash = "sha256:b5ecdd42262ca2462e2624793551e80911a1e989f462910bb81aef974b4bb383"}, ] [package.dependencies] annotated-types = ">=0.4.0" email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""} -pydantic-core = "2.16.3" +pydantic-core = "2.18.1" typing-extensions = ">=4.6.1" [package.extras] @@ -1895,90 +2304,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.16.3" -description = "" +version = "2.18.1" +description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, - {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, - {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, - {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, - {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, - {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, - {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, - {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, - {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, - {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, - {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, - {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, - {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, - {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, + {file = "pydantic_core-2.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ee9cf33e7fe14243f5ca6977658eb7d1042caaa66847daacbd2117adb258b226"}, + {file = "pydantic_core-2.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b7bbb97d82659ac8b37450c60ff2e9f97e4eb0f8a8a3645a5568b9334b08b50"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4249b579e75094f7e9bb4bd28231acf55e308bf686b952f43100a5a0be394c"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d0491006a6ad20507aec2be72e7831a42efc93193d2402018007ff827dc62926"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ae80f72bb7a3e397ab37b53a2b49c62cc5496412e71bc4f1277620a7ce3f52b"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58aca931bef83217fca7a390e0486ae327c4af9c3e941adb75f8772f8eeb03a1"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be91ad664fc9245404a789d60cba1e91c26b1454ba136d2a1bf0c2ac0c0505a"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:667880321e916a8920ef49f5d50e7983792cf59f3b6079f3c9dac2b88a311d17"}, + {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7054fdc556f5421f01e39cbb767d5ec5c1139ea98c3e5b350e02e62201740c7"}, + {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:030e4f9516f9947f38179249778709a460a3adb516bf39b5eb9066fcfe43d0e6"}, + {file = "pydantic_core-2.18.1-cp310-none-win32.whl", hash = "sha256:2e91711e36e229978d92642bfc3546333a9127ecebb3f2761372e096395fc649"}, + {file = "pydantic_core-2.18.1-cp310-none-win_amd64.whl", hash = "sha256:9a29726f91c6cb390b3c2338f0df5cd3e216ad7a938762d11c994bb37552edb0"}, + {file = "pydantic_core-2.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9ece8a49696669d483d206b4474c367852c44815fca23ac4e48b72b339807f80"}, + {file = "pydantic_core-2.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a5d83efc109ceddb99abd2c1316298ced2adb4570410defe766851a804fcd5b"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7973c381283783cd1043a8c8f61ea5ce7a3a58b0369f0ee0ee975eaf2f2a1b"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54c7375c62190a7845091f521add19b0f026bcf6ae674bdb89f296972272e86d"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd63cec4e26e790b70544ae5cc48d11b515b09e05fdd5eff12e3195f54b8a586"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:561cf62c8a3498406495cfc49eee086ed2bb186d08bcc65812b75fda42c38294"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68717c38a68e37af87c4da20e08f3e27d7e4212e99e96c3d875fbf3f4812abfc"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d5728e93d28a3c63ee513d9ffbac9c5989de8c76e049dbcb5bfe4b923a9739d"}, + {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f0f17814c505f07806e22b28856c59ac80cee7dd0fbb152aed273e116378f519"}, + {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d816f44a51ba5175394bc6c7879ca0bd2be560b2c9e9f3411ef3a4cbe644c2e9"}, + {file = "pydantic_core-2.18.1-cp311-none-win32.whl", hash = "sha256:09f03dfc0ef8c22622eaa8608caa4a1e189cfb83ce847045eca34f690895eccb"}, + {file = "pydantic_core-2.18.1-cp311-none-win_amd64.whl", hash = "sha256:27f1009dc292f3b7ca77feb3571c537276b9aad5dd4efb471ac88a8bd09024e9"}, + {file = "pydantic_core-2.18.1-cp311-none-win_arm64.whl", hash = "sha256:48dd883db92e92519201f2b01cafa881e5f7125666141a49ffba8b9facc072b0"}, + {file = "pydantic_core-2.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b6b0e4912030c6f28bcb72b9ebe4989d6dc2eebcd2a9cdc35fefc38052dd4fe8"}, + {file = "pydantic_core-2.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3202a429fe825b699c57892d4371c74cc3456d8d71b7f35d6028c96dfecad31"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3982b0a32d0a88b3907e4b0dc36809fda477f0757c59a505d4e9b455f384b8b"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25595ac311f20e5324d1941909b0d12933f1fd2171075fcff763e90f43e92a0d"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14fe73881cf8e4cbdaded8ca0aa671635b597e42447fec7060d0868b52d074e6"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca976884ce34070799e4dfc6fbd68cb1d181db1eefe4a3a94798ddfb34b8867f"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684d840d2c9ec5de9cb397fcb3f36d5ebb6fa0d94734f9886032dd796c1ead06"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:54764c083bbe0264f0f746cefcded6cb08fbbaaf1ad1d78fb8a4c30cff999a90"}, + {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:201713f2f462e5c015b343e86e68bd8a530a4f76609b33d8f0ec65d2b921712a"}, + {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd1a9edb9dd9d79fbeac1ea1f9a8dd527a6113b18d2e9bcc0d541d308dae639b"}, + {file = "pydantic_core-2.18.1-cp312-none-win32.whl", hash = "sha256:d5e6b7155b8197b329dc787356cfd2684c9d6a6b1a197f6bbf45f5555a98d411"}, + {file = "pydantic_core-2.18.1-cp312-none-win_amd64.whl", hash = "sha256:9376d83d686ec62e8b19c0ac3bf8d28d8a5981d0df290196fb6ef24d8a26f0d6"}, + {file = "pydantic_core-2.18.1-cp312-none-win_arm64.whl", hash = "sha256:c562b49c96906b4029b5685075fe1ebd3b5cc2601dfa0b9e16c2c09d6cbce048"}, + {file = "pydantic_core-2.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3e352f0191d99fe617371096845070dee295444979efb8f27ad941227de6ad09"}, + {file = "pydantic_core-2.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0295d52b012cbe0d3059b1dba99159c3be55e632aae1999ab74ae2bd86a33d7"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56823a92075780582d1ffd4489a2e61d56fd3ebb4b40b713d63f96dd92d28144"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd3f79e17b56741b5177bcc36307750d50ea0698df6aa82f69c7db32d968c1c2"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38a5024de321d672a132b1834a66eeb7931959c59964b777e8f32dbe9523f6b1"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ce426ee691319d4767748c8e0895cfc56593d725594e415f274059bcf3cb76"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2adaeea59849ec0939af5c5d476935f2bab4b7f0335b0110f0f069a41024278e"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9b6431559676a1079eac0f52d6d0721fb8e3c5ba43c37bc537c8c83724031feb"}, + {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:85233abb44bc18d16e72dc05bf13848a36f363f83757541f1a97db2f8d58cfd9"}, + {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:641a018af4fe48be57a2b3d7a1f0f5dbca07c1d00951d3d7463f0ac9dac66622"}, + {file = "pydantic_core-2.18.1-cp38-none-win32.whl", hash = "sha256:63d7523cd95d2fde0d28dc42968ac731b5bb1e516cc56b93a50ab293f4daeaad"}, + {file = "pydantic_core-2.18.1-cp38-none-win_amd64.whl", hash = "sha256:907a4d7720abfcb1c81619863efd47c8a85d26a257a2dbebdb87c3b847df0278"}, + {file = "pydantic_core-2.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:aad17e462f42ddbef5984d70c40bfc4146c322a2da79715932cd8976317054de"}, + {file = "pydantic_core-2.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:94b9769ba435b598b547c762184bcfc4783d0d4c7771b04a3b45775c3589ca44"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80e0e57cc704a52fb1b48f16d5b2c8818da087dbee6f98d9bf19546930dc64b5"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76b86e24039c35280ceee6dce7e62945eb93a5175d43689ba98360ab31eebc4a"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a05db5013ec0ca4a32cc6433f53faa2a014ec364031408540ba858c2172bb0"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:250ae39445cb5475e483a36b1061af1bc233de3e9ad0f4f76a71b66231b07f88"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32204489259786a923e02990249c65b0f17235073149d0033efcebe80095570"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6395a4435fa26519fd96fdccb77e9d00ddae9dd6c742309bd0b5610609ad7fb2"}, + {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2533ad2883f001efa72f3d0e733fb846710c3af6dcdd544fe5bf14fa5fe2d7db"}, + {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b560b72ed4816aee52783c66854d96157fd8175631f01ef58e894cc57c84f0f6"}, + {file = "pydantic_core-2.18.1-cp39-none-win32.whl", hash = "sha256:582cf2cead97c9e382a7f4d3b744cf0ef1a6e815e44d3aa81af3ad98762f5a9b"}, + {file = "pydantic_core-2.18.1-cp39-none-win_amd64.whl", hash = "sha256:ca71d501629d1fa50ea7fa3b08ba884fe10cefc559f5c6c8dfe9036c16e8ae89"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e178e5b66a06ec5bf51668ec0d4ac8cfb2bdcb553b2c207d58148340efd00143"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:72722ce529a76a4637a60be18bd789d8fb871e84472490ed7ddff62d5fed620d"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fe0c1ce5b129455e43f941f7a46f61f3d3861e571f2905d55cdbb8b5c6f5e2c"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4284c621f06a72ce2cb55f74ea3150113d926a6eb78ab38340c08f770eb9b4d"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a0c3e718f4e064efde68092d9d974e39572c14e56726ecfaeebbe6544521f47"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2027493cc44c23b598cfaf200936110433d9caa84e2c6cf487a83999638a96ac"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:76909849d1a6bffa5a07742294f3fa1d357dc917cb1fe7b470afbc3a7579d539"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ee7ccc7fb7e921d767f853b47814c3048c7de536663e82fbc37f5eb0d532224b"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee2794111c188548a4547eccc73a6a8527fe2af6cf25e1a4ebda2fd01cdd2e60"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a139fe9f298dc097349fb4f28c8b81cc7a202dbfba66af0e14be5cfca4ef7ce5"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d074b07a10c391fc5bbdcb37b2f16f20fcd9e51e10d01652ab298c0d07908ee2"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c69567ddbac186e8c0aadc1f324a60a564cfe25e43ef2ce81bcc4b8c3abffbae"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf1c7b78cddb5af00971ad5294a4583188bda1495b13760d9f03c9483bb6203"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2684a94fdfd1b146ff10689c6e4e815f6a01141781c493b97342cdc5b06f4d5d"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:73c1bc8a86a5c9e8721a088df234265317692d0b5cd9e86e975ce3bc3db62a59"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e60defc3c15defb70bb38dd605ff7e0fae5f6c9c7cbfe0ad7868582cb7e844a6"}, + {file = "pydantic_core-2.18.1.tar.gz", hash = "sha256:de9d3e8717560eb05e28739d1b35e4eac2e458553a52a301e51352a7ffc86a35"}, ] [package.dependencies] @@ -2022,13 +2431,13 @@ files = [ [[package]] name = "pyright" -version = "1.1.351" +version = "1.1.358" description = "Command line wrapper for pyright" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.351-py3-none-any.whl", hash = "sha256:83b44b25396ae20661fc5f133c3fce30928ff1296d4f2e5ff0bca5fcf03eb89d"}, - {file = "pyright-1.1.351.tar.gz", hash = "sha256:01124099714eebd7f6525d8cbfa350626b56dfaf771cfcd55c03e69f0f1efbbd"}, + {file = "pyright-1.1.358-py3-none-any.whl", hash = "sha256:0995b6a95eb11bd26f093cd5dee3d5e7258441b1b94d4a171b5dc5b79a1d4f4e"}, + {file = "pyright-1.1.358.tar.gz", hash = "sha256:185524a8d52f6f14bbd3b290b92ad905f25b964dddc9e7148aad760bd35c9f60"}, ] [package.dependencies] @@ -2040,13 +2449,13 @@ dev = ["twine (>=3.4.1)"] [[package]] name = "pytest" -version = "7.4.4" +version = "8.1.1" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, + {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, ] [package.dependencies] @@ -2054,21 +2463,21 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +pluggy = ">=1.4,<2.0" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" -version = "0.23.5" +version = "0.23.6" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.5.tar.gz", hash = "sha256:3a048872a9c4ba14c3e90cc1aa20cbc2def7d01c7c8db3777ec281ba9c057675"}, - {file = "pytest_asyncio-0.23.5-py3-none-any.whl", hash = "sha256:4e7093259ba018d58ede7d5315131d21923a60f8a6e9ee266ce1589685c89eac"}, + {file = "pytest-asyncio-0.23.6.tar.gz", hash = "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f"}, + {file = "pytest_asyncio-0.23.6-py3-none-any.whl", hash = "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a"}, ] [package.dependencies] @@ -2078,6 +2487,24 @@ pytest = ">=7.0.0,<9" docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] +[[package]] +name = "pytest-cov" +version = "5.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + [[package]] name = "pytest-httpx" version = "0.30.0" @@ -2096,6 +2523,23 @@ pytest = ">=7,<9" [package.extras] testing = ["pytest-asyncio (==0.23.*)", "pytest-cov (==4.*)"] +[[package]] +name = "pytest-mock" +version = "3.14.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + [[package]] name = "pyunormalize" version = "15.1.0" @@ -2191,13 +2635,13 @@ files = [ [[package]] name = "referencing" -version = "0.33.0" +version = "0.34.0" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, - {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, + {file = "referencing-0.34.0-py3-none-any.whl", hash = "sha256:d53ae300ceddd3169f1ffa9caf2cb7b769e92657e4fafb23d34b93679116dfd4"}, + {file = "referencing-0.34.0.tar.gz", hash = "sha256:5773bd84ef41799a5a8ca72dc34590c041eb01bf9aa02632b4a973fb0181a844"}, ] [package.dependencies] @@ -2327,6 +2771,24 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "rich" +version = "13.7.1" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + [[package]] name = "rlp" version = "4.0.0" @@ -2457,46 +2919,82 @@ files = [ [[package]] name = "ruff" -version = "0.2.2" +version = "0.3.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"}, - {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"}, - {file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"}, - {file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"}, - {file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"}, - {file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"}, - {file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"}, - {file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"}, + {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e8377cccb2f07abd25e84fc5b2cbe48eeb0fea9f1719cad7caedb061d70e5ce"}, + {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:15a4d1cc1e64e556fa0d67bfd388fed416b7f3b26d5d1c3e7d192c897e39ba4b"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d28bdf3d7dc71dd46929fafeec98ba89b7c3550c3f0978e36389b5631b793663"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:379b67d4f49774ba679593b232dcd90d9e10f04d96e3c8ce4a28037ae473f7bb"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c060aea8ad5ef21cdfbbe05475ab5104ce7827b639a78dd55383a6e9895b7c51"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ebf8f615dde968272d70502c083ebf963b6781aacd3079081e03b32adfe4d58a"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48098bd8f5c38897b03604f5428901b65e3c97d40b3952e38637b5404b739a2"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da8a4fda219bf9024692b1bc68c9cff4b80507879ada8769dc7e985755d662ea"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c44e0149f1d8b48c4d5c33d88c677a4aa22fd09b1683d6a7ff55b816b5d074f"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3050ec0af72b709a62ecc2aca941b9cd479a7bf2b36cc4562f0033d688e44fa1"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a29cc38e4c1ab00da18a3f6777f8b50099d73326981bb7d182e54a9a21bb4ff7"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b15cc59c19edca917f51b1956637db47e200b0fc5e6e1878233d3a938384b0b"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e491045781b1e38b72c91247cf4634f040f8d0cb3e6d3d64d38dcf43616650b4"}, + {file = "ruff-0.3.7-py3-none-win32.whl", hash = "sha256:bc931de87593d64fad3a22e201e55ad76271f1d5bfc44e1a1887edd0903c7d9f"}, + {file = "ruff-0.3.7-py3-none-win_amd64.whl", hash = "sha256:5ef0e501e1e39f35e03c2acb1d1238c595b8bb36cf7a170e7c1df1b73da00e74"}, + {file = "ruff-0.3.7-py3-none-win_arm64.whl", hash = "sha256:789e144f6dc7019d1f92a812891c645274ed08af6037d11fc65fcbc183b7d59f"}, + {file = "ruff-0.3.7.tar.gz", hash = "sha256:d5c1aebee5162c2226784800ae031f660c350e7a3402c4d1f8ea4e97e232e3ba"}, +] + +[[package]] +name = "safe-pysha3" +version = "1.0.4" +description = "SHA-3 (Keccak) for Python 3.9 - 3.11" +optional = false +python-versions = "*" +files = [ + {file = "safe-pysha3-1.0.4.tar.gz", hash = "sha256:e429146b1edd198b2ca934a2046a65656c5d31b0ec894bbd6055127f4deaff17"}, ] +[[package]] +name = "semantic-version" +version = "2.10.0" +description = "A library implementing the 'SemVer' scheme." +optional = false +python-versions = ">=2.7" +files = [ + {file = "semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177"}, + {file = "semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c"}, +] + +[package.extras] +dev = ["Django (>=1.11)", "check-manifest", "colorama (<=0.4.1)", "coverage", "flake8", "nose2", "readme-renderer (<25.0)", "tox", "wheel", "zest.releaser[recommended]"] +doc = ["Sphinx", "sphinx-rtd-theme"] + [[package]] name = "setuptools" -version = "69.1.1" +version = "69.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, - {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, + {file = "setuptools-69.2.0-py3-none-any.whl", hash = "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c"}, + {file = "setuptools-69.2.0.tar.gz", hash = "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + [[package]] name = "six" version = "1.16.0" @@ -2519,6 +3017,17 @@ files = [ {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +optional = false +python-versions = "*" +files = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] + [[package]] name = "stack-data" version = "0.6.3" @@ -2560,6 +3069,17 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "tomlkit" +version = "0.12.4" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.4-py3-none-any.whl", hash = "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b"}, + {file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3"}, +] + [[package]] name = "toolz" version = "0.12.1" @@ -2573,28 +3093,68 @@ files = [ [[package]] name = "traitlets" -version = "5.14.1" +version = "5.14.2" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, - {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, + {file = "traitlets-5.14.2-py3-none-any.whl", hash = "sha256:fcdf85684a772ddeba87db2f398ce00b40ff550d1528c03c14dbf6a02003cd80"}, + {file = "traitlets-5.14.2.tar.gz", hash = "sha256:8cdd83c040dab7d1dee822678e5f5d100b514f7b72b01615b26fc5718916fdf9"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.1)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "trie" +version = "3.0.0" +description = "Python implementation of the Ethereum Trie structure" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "trie-3.0.0-py3-none-any.whl", hash = "sha256:a061507aa3a0076c61a65c0d70de528508a66d948f09054de51f6560fd59c454"}, + {file = "trie-3.0.0.tar.gz", hash = "sha256:180205883dc614cade519b38b3e4ffecb8184e53d594556b38f43446c5cda840"}, +] + +[package.dependencies] +eth-hash = ">=0.1.0" +eth-utils = ">=2.0.0" +hexbytes = ">=0.2.0,<0.4.0" +rlp = ">=3" +sortedcontainers = ">=2.1.0" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash (>=0.1.0,<1.0.0)", "hypothesis (>=6.56.4,<7)", "ipython", "pre-commit (>=3.4.0)", "pycryptodome", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["towncrier (>=21,<22)"] +test = ["hypothesis (>=6.56.4,<7)", "pycryptodome", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "typer" +version = "0.12.3" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.7" +files = [ + {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"}, + {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"}, +] + +[package.dependencies] +click = ">=8.0.0" +rich = ">=10.11.0" +shellingham = ">=1.3.0" +typing-extensions = ">=3.7.4.3" [[package]] name = "typing-extensions" -version = "4.10.0" +version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, - {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] [[package]] @@ -2647,13 +3207,13 @@ files = [ [[package]] name = "web3" -version = "6.15.1" +version = "6.17.0" description = "web3.py" optional = false python-versions = ">=3.7.2" files = [ - {file = "web3-6.15.1-py3-none-any.whl", hash = "sha256:4e4a8313aa4556ecde61c852a62405b853b667498b07da6ff05c29fe8c79096b"}, - {file = "web3-6.15.1.tar.gz", hash = "sha256:f9e7eefc1b3c3d194868a4ef9583b625c18ea3f31a48ebe143183db74898f381"}, + {file = "web3-6.17.0-py3-none-any.whl", hash = "sha256:37334971dc195d0b3fb930317b63a36b0f71e6a0fd30deca96f1ac58e65704c0"}, + {file = "web3-6.17.0.tar.gz", hash = "sha256:1b535272a40da3d8d2b120856edb53b84b0c08bcc8fe1a5bbd5f816fd72f4ec6"}, ] [package.dependencies] @@ -2661,12 +3221,14 @@ aiohttp = ">=3.7.4.post0" eth-abi = ">=4.0.0" eth-account = ">=0.8.0" eth-hash = {version = ">=0.5.1", extras = ["pycryptodome"]} -eth-typing = ">=3.0.0" +eth-tester = {version = ">=0.11.0b1,<0.12.0b1", extras = ["py-evm"], optional = true, markers = "python_version > \"3.7\" and extra == \"tester\""} +eth-typing = ">=3.0.0,<4.2.0" eth-utils = ">=2.1.0" hexbytes = ">=0.1.0,<0.4.0" jsonschema = ">=4.0.0" lru-dict = ">=1.1.6,<1.3.0" protobuf = ">=4.21.6" +py-geth = {version = ">=3.14.0", optional = true, markers = "extra == \"tester\""} pyunormalize = ">=15.0.0" pywin32 = {version = ">=223", markers = "platform_system == \"Windows\""} requests = ">=2.16.0" @@ -2674,11 +3236,10 @@ typing-extensions = ">=4.0.1" websockets = ">=10.0.0" [package.extras] -dev = ["black (>=22.1.0)", "build (>=0.9.0)", "bumpversion", "eth-tester[py-evm] (==v0.9.1-b.2)", "flake8 (==3.8.3)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "importlib-metadata (<5.0)", "ipfshttpclient (==0.8.0a2)", "isort (>=5.11.0)", "mypy (==1.4.1)", "py-geth (>=3.14.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-watch (>=4.2)", "pytest-xdist (>=1.29)", "setuptools (>=38.6.0)", "sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=3.18.0)", "tqdm (>4.32)", "twine (>=1.13)", "types-protobuf (==3.19.13)", "types-requests (>=2.26.1)", "types-setuptools (>=57.4.4)", "when-changed (>=0.3.0)"] +dev = ["build (>=0.9.0)", "bumpversion", "eth-tester[py-evm] (>=0.11.0b1,<0.12.0b1)", "eth-tester[py-evm] (>=0.9.0b1,<0.10.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "importlib-metadata (<5.0)", "ipfshttpclient (==0.8.0a2)", "pre-commit (>=2.21.0)", "py-geth (>=3.14.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-watch (>=4.2)", "pytest-xdist (>=1.29)", "setuptools (>=38.6.0)", "sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=3.18.0)", "tqdm (>4.32)", "twine (>=1.13)", "when-changed (>=0.3.0)"] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] ipfs = ["ipfshttpclient (==0.8.0a2)"] -linter = ["black (>=22.1.0)", "flake8 (==3.8.3)", "isort (>=5.11.0)", "mypy (==1.4.1)", "types-protobuf (==3.19.13)", "types-requests (>=2.26.1)", "types-setuptools (>=57.4.4)"] -tester = ["eth-tester[py-evm] (==v0.9.1-b.2)", "py-geth (>=3.14.0)"] +tester = ["eth-tester[py-evm] (>=0.11.0b1,<0.12.0b1)", "eth-tester[py-evm] (>=0.9.0b1,<0.10.0b1)", "py-geth (>=3.14.0)"] [[package]] name = "websockets" @@ -2866,5 +3427,5 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" -python-versions = ">=3.9,<4.0" -content-hash = "93cf4e96a5a1bbb2e12255948052244de86a28c381d41abd1800a5d13126fdba" +python-versions = ">=3.10,<4.0" +content-hash = "0031ce486f3306874d8727c52197a6389c3a64d7d97acec9b4f08c0682996f99" diff --git a/pyproject.toml b/pyproject.toml index 0ca75ce..012d3ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,43 +6,53 @@ authors = ["José Ribeiro "] readme = "README.md" [tool.poetry.dependencies] -python = ">=3.9,<4.0" +python = ">=3.10,<4.0" httpx = "^0.27.0" web3 = "^6.15.1" pybars3 = "^0.9.7" -pydantic = "^2.6.2" +pydantic = "^2.7.0" +pytest-mock = "^3.14.0" +backoff = "^2.2.1" +aiolimiter = "^1.1.0" [tool.poetry.group.dev.dependencies] -ruff = "^0.2.2" -pyright ="^1.1.296" -pytest ="^7.2.1" -ipython = "*" -pre-commit = "3.*" -datamodel-code-generator = "^0.25.4" -ariadne-codegen = "^0.12.0" +ruff = "^0.3.7" +pyright = "^1.1.358" +pytest = "^8.1.1" +ipython = "^8.23.0" +pre-commit = "^3.7.0" +datamodel-code-generator = "^0.25.5" +ariadne-codegen = "^0.13.0" pytest-httpx = "^0.30.0" -pytest-asyncio = "^0.23.5" +pytest-asyncio = "^0.23.6" +web3 = { extras = ["tester"], version = "^6.17.0" } +pycln = "^2.4.0" +pytest-cov = "^5.0.0" [tool.poetry.scripts] -web3_codegen = 'cow_py.codegen.main:main' [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.ariadne-codegen] -remote_schema_url= "https://api.thegraph.com/subgraphs/name/cowprotocol/cow" +remote_schema_url = "https://api.thegraph.com/subgraphs/name/cowprotocol/cow" queries_path = "cow_py/subgraph/queries" -target_package_name="client" -target_package_path="cow_py/subgraph" -client_name="SubgraphClient" -client_file_name="subgraph_client" +target_package_name = "client" +target_package_path = "cow_py/subgraph" +client_name = "SubgraphClient" +client_file_name = "subgraph_client" [tool.pyright] # NOTE: these paths are excluded but not IGNORED. They are still included in the analysis if they are referenced by source files that are not excluded. -exclude = ["**/node_modules", +exclude = [ + "**/node_modules", "**/__pycache__", "cow_py/subgraph/client/*.py", - "cow_py/order_book/__generated__/*.py" + "cow_py/order_book/generated/*.py", + ".venv/", + "**/__generated__" ] +reportIncompatibleVariableOverride = 'warning' +strictParameterNoneValue = false diff --git a/tests/codegen/components/test_base_contract.py b/tests/codegen/components/test_base_contract.py new file mode 100644 index 0000000..40cab69 --- /dev/null +++ b/tests/codegen/components/test_base_contract.py @@ -0,0 +1,21 @@ +# tests/codegen/components/test_base_contract.py + + +def test_base_contract_singleton(): + # Test that BaseContract follows the singleton pattern + pass + + +def test_base_contract_function_exists_in_abi(): + # Test that BaseContract._function_exists_in_abi correctly checks function existence + pass + + +def test_base_contract_event_exists_in_abi(): + # Test that BaseContract._event_exists_in_abi correctly checks event existence + pass + + +def test_base_contract_getattr(): + # Test that BaseContract.__getattr__ correctly handles attribute access + pass diff --git a/tests/codegen/components/test_contract_factory.py b/tests/codegen/components/test_contract_factory.py new file mode 100644 index 0000000..18ea6b5 --- /dev/null +++ b/tests/codegen/components/test_contract_factory.py @@ -0,0 +1,11 @@ +# tests/codegen/components/test_contract_factory.py + + +def test_contract_factory_get_contract_class(): + # Test that ContractFactory.get_contract_class correctly retrieves or creates contract class + pass + + +def test_contract_factory_create(): + # Test that ContractFactory.create correctly creates an instance of the contract class + pass diff --git a/tests/codegen/test_abi_handler.py b/tests/codegen/test_abi_handler.py index 841d88d..6a1d7e6 100644 --- a/tests/codegen/test_abi_handler.py +++ b/tests/codegen/test_abi_handler.py @@ -1,4 +1,5 @@ import pytest + from cow_py.codegen.abi_handler import to_python_conventional_name @@ -16,3 +17,48 @@ ) def test_to_python_conventional_name(input_name, expected_output): assert to_python_conventional_name(input_name) == expected_output + + +def test_compile_partial(): + # Test that compile_partial correctly compiles a partial template + pass + + +def test_get_filename_without_extension(): + # Test that get_filename_without_extension correctly removes the extension + pass + + +def test_get_template_file(): + # Test that _get_template_file returns the correct template file path + pass + + +def test_get_partials_files(): + # Test that _get_partials_files returns the correct list of partial files + pass + + +def test_abi_handler_generate(): + # Test that ABIHandler.generate correctly generates Python code from an ABI + pass + + +def test_abi_handler_prepare_template_data(): + # Test that ABIHandler._prepare_template_data correctly processes the ABI + pass + + +def test_abi_handler_process_parameters(): + # Test that ABIHandler._process_parameters correctly processes function parameters + pass + + +def test_abi_handler_process_function(): + # Test that ABIHandler._process_function correctly processes a function item + pass + + +def test_abi_handler_render_template(): + # Test that ABIHandler._render_template correctly renders the template with data + pass diff --git a/tests/codegen/test_solidity_converter.py b/tests/codegen/test_solidity_converter.py new file mode 100644 index 0000000..8324b2d --- /dev/null +++ b/tests/codegen/test_solidity_converter.py @@ -0,0 +1,84 @@ +import pytest + +from cow_py.codegen.solidity_converter import SolidityConverter, SolidityConverterError + + +def test_solidity_converter_get_struct_name(): + internal_type = "struct MyStruct" + expected_result = "MyStruct" + result = SolidityConverter._get_struct_name(internal_type) + assert result == expected_result + + +def test_solidity_converter_get_struct_name_invalid_internal_type(): + internal_type = "uint256" + with pytest.raises(SolidityConverterError): + SolidityConverter._get_struct_name(internal_type) + + +def test_solidity_converter_convert_type_enum(): + solidity_type = "enum MyEnum" + internal_type = "" + expected_result = "MyEnum" + result = SolidityConverter.convert_type(solidity_type, internal_type) + assert result == expected_result + + +def test_solidity_converter_convert_type_array(): + solidity_type = "uint256[]" + internal_type = "" + expected_result = "List[int]" + result = SolidityConverter.convert_type(solidity_type, internal_type) + assert result == expected_result + + +def test_solidity_converter_convert_type_tuple(): + solidity_type = "tuple" + internal_type = "struct MyStruct" + expected_result = "MyStruct" + result = SolidityConverter.convert_type(solidity_type, internal_type) + assert result == expected_result + + +def test_solidity_converter_convert_type_fixed_size_array(): + solidity_type = "uint256[3]" + internal_type = "" + expected_result = "Tuple[int, int, int]" + result = SolidityConverter.convert_type(solidity_type, internal_type) + assert result == expected_result + + +def test_solidity_converter_convert_type_unknown_type(): + solidity_type = "unknown_type" + internal_type = "" + expected_result = "Any" + result = SolidityConverter.convert_type(solidity_type, internal_type) + assert result == expected_result + + +def test_solidity_converter_extract_enum_name(): + internal_type = "enum MyEnum.Option" + expected_result = "MyEnum_Option" + result = SolidityConverter._extract_enum_name(internal_type) + assert result == expected_result + + +def test_solidity_converter_convert_array_or_basic_type_dynamic_array(): + solidity_type = "address[]" + expected_result = "List[str]" + result = SolidityConverter._convert_array_or_basic_type(solidity_type) + assert result == expected_result + + +def test_solidity_converter_convert_array_or_basic_type_fixed_size_array(): + solidity_type = "bool[5]" + expected_result = "Tuple[bool, bool, bool, bool, bool]" + result = SolidityConverter._convert_array_or_basic_type(solidity_type) + assert result == expected_result + + +def test_solidity_converter_convert_array_or_basic_type_basic_type(): + solidity_type = "bytes32" + expected_result = "HexBytes" + result = SolidityConverter._convert_array_or_basic_type(solidity_type) + assert result == expected_result diff --git a/tests/core/__init__.py b/tests/common/__init__.py similarity index 100% rename from tests/core/__init__.py rename to tests/common/__init__.py diff --git a/tests/common/api/test_api_base.py b/tests/common/api/test_api_base.py new file mode 100644 index 0000000..1c3dd9f --- /dev/null +++ b/tests/common/api/test_api_base.py @@ -0,0 +1,129 @@ +from unittest.mock import AsyncMock, Mock, patch + +import httpx +import pytest + +from cow_py.common.api.api_base import ApiBase, APIConfig +from cow_py.common.api.decorators import DEFAULT_BACKOFF_OPTIONS +from cow_py.common.config import SupportedChainId +from httpx import Request + +ERROR_MESSAGE = "💣💥 Booom!" +OK_RESPONSE = {"status": 200, "ok": True, "content": {"some": "data"}} + + +@pytest.fixture +def sut(): + class MyConfig(APIConfig): + def __init__(self): + super().__init__(SupportedChainId.SEPOLIA, None) + + def get_base_url(self): + return "http://localhost" + + class MyAPI(ApiBase): + @staticmethod + def get_config(context): + return Mock( + chain_id="mainnet", get_base_url=Mock(return_value="http://localhost") + ) + + async def get_version(self, context_override={}): + return await self._fetch( + path="/api/v1/version", context_override=context_override + ) + + return MyAPI(config=MyConfig()) + + +@pytest.fixture +def mock_success_response(): + return AsyncMock( + status_code=200, + headers={"content-type": "application/json"}, + json=Mock(return_value=OK_RESPONSE), + ) + + +@pytest.fixture +def mock_http_status_error(): + return httpx.HTTPStatusError( + message=ERROR_MESSAGE, + request=Request("GET", "http://example.com"), + response=httpx.Response(500), + ) + + +@pytest.mark.asyncio +async def test_no_re_attempt_if_success(sut, mock_success_response): + with patch( + "httpx.AsyncClient.send", side_effect=[mock_success_response] + ) as mock_request: + response = await sut.get_version() + assert mock_request.awaited_once() + assert response["content"]["some"] == "data" + + +@pytest.mark.asyncio +async def test_re_attempts_if_fails_then_succeeds( + sut, mock_success_response, mock_http_status_error +): + with patch( + "httpx.AsyncClient.send", + side_effect=[ + *([mock_http_status_error] * 3), + mock_success_response, + ], + ) as mock_request: + response = await sut.get_version() + + assert response["ok"] is True + assert mock_request.call_count == 4 + + +@pytest.mark.asyncio +async def test_succeeds_last_attempt( + sut, mock_success_response, mock_http_status_error +): + with patch( + "httpx.AsyncClient.send", + side_effect=[ + mock_http_status_error, + mock_http_status_error, + mock_success_response, + ], + ) as mock_send: + response = await sut.get_version() + assert response["ok"] is True + assert mock_send.call_count == 3 + + +@pytest.mark.asyncio +async def test_does_not_reattempt_after_max_failures(sut, mock_http_status_error): + with patch( + "httpx.AsyncClient.request", side_effect=[mock_http_status_error] * 3 + ) as mock_call: + with pytest.raises(httpx.HTTPStatusError): + await sut.get_version(context_override={"backoff_opts": {"max_tries": 3}}) + + assert mock_call.call_count == 3 + + +@pytest.mark.asyncio +async def test_backoff_uses_function_options_instead_of_default( + sut, mock_http_status_error +): + max_tries = 1 + + assert max_tries != DEFAULT_BACKOFF_OPTIONS["max_tries"] + + with patch( + "httpx.AsyncClient.request", + side_effect=[mock_http_status_error] * max_tries, + ) as mock_call: + with pytest.raises(httpx.HTTPStatusError): + await sut.get_version( + context_override={"backoff_opts": {"max_tries": max_tries}} + ) + + assert mock_call.call_count == max_tries diff --git a/tests/common/api/test_rate_limiter.py b/tests/common/api/test_rate_limiter.py new file mode 100644 index 0000000..1e6ca12 --- /dev/null +++ b/tests/common/api/test_rate_limiter.py @@ -0,0 +1,28 @@ +import asyncio + +import pytest + +from cow_py.common.api.decorators import rate_limitted + + +@pytest.mark.asyncio +async def test_call_intervals(): + async def test_function(): + return "called" + + # Set the rate limit for easy calculation (e.g., 2 calls per second) + decorated_function = rate_limitted(2, 1)(test_function) + + call_times = [] + + # Perform a number of calls and record the time each was completed + for _ in range(6): + await decorated_function() + call_times.append(asyncio.get_event_loop().time()) + + # Verify intervals between calls are as expected (at least 0.5 seconds apart after the first batch of 2) + intervals = [call_times[i] - call_times[i - 1] for i in range(1, len(call_times))] + for interval in intervals[2:]: # Ignore the first two immediate calls + assert ( + interval >= 0.5 + ), f"Interval of {interval} too short, should be at least 0.5" diff --git a/tests/core/test_core_api.py b/tests/common/test_core_api.py similarity index 70% rename from tests/core/test_core_api.py rename to tests/common/test_core_api.py index f03dd13..992d22d 100644 --- a/tests/core/test_core_api.py +++ b/tests/common/test_core_api.py @@ -1,5 +1,6 @@ import pytest -from cow_py.common import constants, cow_error, chains, config + +from cow_py.common import chains, config, constants, cow_error @pytest.mark.parametrize("module", [constants, cow_error, chains, config]) diff --git a/tests/core/test_cow_error.py b/tests/common/test_cow_error.py similarity index 62% rename from tests/core/test_cow_error.py rename to tests/common/test_cow_error.py index aada517..31c3aaa 100644 --- a/tests/core/test_cow_error.py +++ b/tests/common/test_cow_error.py @@ -1,15 +1,11 @@ -from cow_py.common.cow_error import ( - CowError, -) # Adjust the import path according to your project structure +from cow_py.common.cow_error import CowError def test_cow_error_inheritance(): - # Test that CowError is a subclass of Exception assert issubclass(CowError, Exception) def test_cow_error_initialization(): - # Test CowError initialization with a message and error_code message = "An error occurred" error_code = 1001 error = CowError(message, error_code) @@ -19,7 +15,6 @@ def test_cow_error_initialization(): def test_cow_error_initialization_without_error_code(): - # Test CowError initialization with only a message message = "An error occurred" error = CowError(message) diff --git a/tests/contracts/conftest.py b/tests/contracts/conftest.py new file mode 100644 index 0000000..98af89f --- /dev/null +++ b/tests/contracts/conftest.py @@ -0,0 +1,39 @@ +from eth_utils.conversions import to_hex +from eth_utils.crypto import keccak +from eth_utils.currency import to_wei + +from cow_py.contracts.order import Order + + +def fill_bytes(count, byte): + return to_hex(bytearray([byte] * count)) + + +def fill_distinct_bytes(count, start): + return to_hex(bytearray([(start + i) % 256 for i in range(count)])) + + +def fill_uint(bits, byte): + return int(fill_bytes(bits // 8, byte), 16) + + +def ceil_div(p, q): + return (p + q - 1) // q + + +ORDER_KIND_SELL = "SELL" + +SAMPLE_ORDER = Order( + **{ + "sellToken": fill_bytes(20, 0x01), + "buyToken": fill_bytes(20, 0x02), + "receiver": fill_bytes(20, 0x03), + "sellAmount": to_wei("42", "ether"), + "buyAmount": to_wei("13.37", "ether"), + "validTo": 0xFFFFFFFF, + "appData": keccak(text="")[0:20], + "feeAmount": to_wei("1.0", "ether"), + "kind": ORDER_KIND_SELL, + "partiallyFillable": False, + } +) diff --git a/tests/contracts/test_orders.py b/tests/contracts/test_orders.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/contracts/test_sign.py b/tests/contracts/test_sign.py new file mode 100644 index 0000000..0371f2a --- /dev/null +++ b/tests/contracts/test_sign.py @@ -0,0 +1,78 @@ +import pytest +from eth_account.messages import SignableMessage +from eth_account.signers.local import LocalAccount +from eth_utils.conversions import to_hex +from web3 import EthereumTesterProvider, Web3 + +from cow_py.contracts.order import hash_order_cancellation + +# Assuming you have these Python equivalents of your TypeScript code +from cow_py.contracts.sign import SigningScheme, sign_order, sign_order_cancellation + +from .conftest import SAMPLE_ORDER + +# Setup Web3 and Ethereum Tester (or use your existing setup) +w3 = Web3(EthereumTesterProvider()) + + +def patched_sign_message_builder(account: LocalAccount): + def sign_message(message): + # Determine the correct message format + if isinstance(message, SignableMessage): + message_to_hash = message.body + elif isinstance(message, (bytes, str)): + message_to_hash = message + else: + raise TypeError("Unsupported message type for signing.") + + # Hash and sign the message + message_hash = Web3.solidity_keccak(["bytes"], [message_to_hash]) + signature = account.signHash(message_hash) + r, s, v = signature["r"], signature["s"], signature["v"] + + # Adjust v to be 27 or 28 + v_adjusted = v + 27 if v < 27 else v + + # Concatenate the signature components into a hex string + signature_hex = to_hex(r)[2:] + to_hex(s)[2:] + hex(v_adjusted)[2:] + + return signature_hex + + return sign_message + + +@pytest.mark.asyncio +@pytest.mark.parametrize("scheme", [SigningScheme.EIP712, SigningScheme.ETHSIGN]) +async def test_sign_order(monkeypatch, scheme): + signer = w3.eth.account.create() + + patched_sign_message = patched_sign_message_builder(signer) + + # Use monkeypatch to temporarily replace sign_message + monkeypatch.setattr(signer, "sign_message", patched_sign_message) + + domain = {"name": "test"} + signed_order = sign_order(domain, SAMPLE_ORDER, signer, scheme) + + # Extract 'v' value from the last two characters of the signature + v = signed_order.data[-2:] + + assert v in ["1b", "1c"] + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "scheme", [SigningScheme.EIP712.value, SigningScheme.ETHSIGN.value] +) +async def test_sign_order_cancellation(scheme): + signer = w3.eth.account.create() + domain = {"name": "test"} + order_uid = "0x" + "2a" * 56 + + signature_data = sign_order_cancellation(domain, order_uid, signer, scheme) + order_hash = hash_order_cancellation(domain, order_uid) + + assert ( + w3.eth.account._recover_hash(order_hash, signature=signature_data.data) + == signer.address + ) diff --git a/tests/order_book/test_api.py b/tests/order_book/test_api.py new file mode 100644 index 0000000..72f5d22 --- /dev/null +++ b/tests/order_book/test_api.py @@ -0,0 +1,147 @@ +from unittest.mock import AsyncMock, Mock, patch + +import pytest + +from cow_py.order_book.api import OrderBookApi +from cow_py.order_book.generated.model import OrderQuoteSide1 +from cow_py.order_book.generated.model import OrderQuoteSideKindSell +from cow_py.order_book.generated.model import TokenAmount +from cow_py.order_book.generated.model import ( + OrderQuoteRequest, + OrderQuoteResponse, + Trade, + OrderCreation, +) + + +@pytest.fixture +def order_book_api(): + return OrderBookApi() + + +@pytest.mark.asyncio +async def test_get_version(order_book_api): + expected_version = "1.0.0" + with patch("httpx.AsyncClient.request", new_callable=AsyncMock) as mock_request: + mock_request.return_value = AsyncMock( + status_code=200, + text=expected_version, + ) + version = await order_book_api.get_version() + + mock_request.assert_awaited_once() + assert version == expected_version + + +@pytest.mark.asyncio +async def test_get_trades_by_order_uid(order_book_api): + mock_trade_data = [ + { + "blockNumber": 123456, + "logIndex": 789, + "orderUid": "mock_order_uid", + "owner": "mock_owner_address", + "sellToken": "mock_sell_token_address", + "buyToken": "mock_buy_token_address", + "sellAmount": "100", + "sellAmountBeforeFees": "120", + "buyAmount": "200", + "txHash": "mock_transaction_hash", + } + ] + mock_trade = Trade(**mock_trade_data[0]) + with patch("httpx.AsyncClient.request", new_callable=AsyncMock) as mock_request: + mock_request.return_value = AsyncMock( + status_code=200, + headers={"content-type": "application/json"}, + json=Mock(return_value=mock_trade_data), + ) + trades = await order_book_api.get_trades_by_order_uid("mock_order_uid") + mock_request.assert_awaited_once() + assert trades == [mock_trade] + + +@pytest.mark.asyncio +async def test_post_quote(order_book_api): + mock_order_quote_request = OrderQuoteRequest( + **{ + "sellToken": "0x", + "buyToken": "0x", + "receiver": "0x", + "appData": "app_data_object", + "appDataHash": "0x", + "from": "0x", + "priceQuality": "verified", + "signingScheme": "eip712", + "onchainOrder": False, + } + ) + + mock_order_quote_side = OrderQuoteSide1( + sellAmountBeforeFee=TokenAmount("0"), kind=OrderQuoteSideKindSell.sell + ) + mock_order_quote_response_data = { + "quote": { + "sellToken": "0x", + "buyToken": "0x", + "receiver": "0x", + "sellAmount": "0", + "buyAmount": "0", + "feeAmount": "0", + "validTo": 0, + "appData": "0x", + "partiallyFillable": True, + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + "kind": "buy", + }, + "verified": True, + "from": "0x", + "expiration": "0", + } + mock_order_quote_response = OrderQuoteResponse(**mock_order_quote_response_data) + with patch("httpx.AsyncClient.request", new_callable=AsyncMock) as mock_request: + mock_request.return_value = AsyncMock( + status_code=200, + headers={"content-type": "application/json"}, + json=Mock(return_value=mock_order_quote_response_data), + ) + response = await order_book_api.post_quote( + mock_order_quote_request, mock_order_quote_side + ) + mock_request.assert_awaited_once() + assert response == mock_order_quote_response + + +@pytest.mark.asyncio +async def test_post_order(order_book_api): + mock_response = "mock_uid" + mock_order_creation = OrderCreation( + **{ + "sellToken": "0x", + "buyToken": "0x", + "sellAmount": "0", + "buyAmount": "0", + "validTo": 0, + "feeAmount": "0", + "kind": "buy", + "partiallyFillable": True, + "appData": "0x", + "signingScheme": "eip712", + "signature": "0x", + "receiver": "0x", + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + "quoteId": 0, + "appDataHash": "0x", + "from_": "0x", + } + ) + with patch("httpx.AsyncClient.request", new_callable=AsyncMock) as mock_request: + mock_request.return_value = AsyncMock( + status_code=200, + text=mock_response, + ) + response = await order_book_api.post_order(mock_order_creation) + mock_request.assert_awaited_once() + assert response.root == mock_response diff --git a/tests/subgraph/client/test_subgraph_client.py b/tests/subgraph/client/test_subgraph_client.py index 68c4dbd..6bc57e4 100644 --- a/tests/subgraph/client/test_subgraph_client.py +++ b/tests/subgraph/client/test_subgraph_client.py @@ -1,18 +1,17 @@ -from cow_py.subgraph.client import SubgraphClient - -from pytest_httpx import HTTPXMock import pytest +from pytest_httpx import HTTPXMock + +from cow_py.subgraph.client import SubgraphClient +from cow_py.subgraph.client.exceptions import GraphQLClientGraphQLMultiError from cow_py.subgraph.client.last_days_volume import ( LastDaysVolume, LastDaysVolumeDailyTotals, ) - -from cow_py.subgraph.client.totals import Totals, TotalsTotals from cow_py.subgraph.client.last_hours_volume import ( LastHoursVolume, LastHoursVolumeHourlyTotals, ) -from cow_py.subgraph.client.exceptions import GraphQLClientGraphQLMultiError +from cow_py.subgraph.client.totals import Totals, TotalsTotals @pytest.mark.asyncio diff --git a/tests/subgraph/test_deployments.py b/tests/subgraph/test_deployments.py index d868112..2fd097b 100644 --- a/tests/subgraph/test_deployments.py +++ b/tests/subgraph/test_deployments.py @@ -1,10 +1,11 @@ import pytest + from cow_py.common.chains import Chain from cow_py.subgraph.deployments import ( - build_subgraph_url, + SUBGRAPH_BASE_URL, SubgraphConfig, SubgraphEnvironment, - SUBGRAPH_BASE_URL, + build_subgraph_url, )