diff --git a/.github/tentative_workflows/test_factory.yaml b/.github/tentative_workflows/test_factory.yaml deleted file mode 100644 index ed7eca94..00000000 --- a/.github/tentative_workflows/test_factory.yaml +++ /dev/null @@ -1,49 +0,0 @@ -name: test_factory - -on: - pull_request: - paths: - - "tests/test_factory.py" - - "contracts/CurveStableSwapFactoryNG.vy" - push: - paths: - - "tests/test_factory.py" - - "contracts/CurveStableSwapFactoryNG.vy" - -env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - WEB3_PROVIDER_URL: ${{ secrets.WEB3_PROVIDER_URL }} - -jobs: - tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Cache Compiler Installations - uses: actions/cache@v3 - with: - path: | - ~/.vvm - key: compiler-cache - - - name: Setup Python 3.10.4 - uses: actions/setup-python@v4 - with: - python-version: 3.10.4 - - - name: Install Requirements - run: | - pip install poetry==1.5.1 - poetry config virtualenvs.in-project true - poetry install --no-interaction --without dev - - - name: Run Tests Basic - run: | - source .venv/bin/activate - pytest tests/test_factory.py --token-types=plain -n auto - - - name: Run Tests Forked - run: | - source .venv/bin/activate - pytest tests/test_factory_forked.py --token-types=plain -n auto diff --git a/.github/tentative_workflows/test_gauge.yaml b/.github/tentative_workflows/test_gauge.yaml deleted file mode 100644 index fbb3f03c..00000000 --- a/.github/tentative_workflows/test_gauge.yaml +++ /dev/null @@ -1,44 +0,0 @@ -name: test_gauge - -on: - pull_request: - paths: - - "tests/gauge/*.py" - - "contracts/LiquidityGauge.vy" - push: - paths: - - "tests/gauge/*.py" - - "contracts/LiquidityGauge.vy" - -env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - WEB3_PROVIDER_URL: ${{ secrets.WEB3_PROVIDER_URL }} - -jobs: - tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Cache Compiler Installations - uses: actions/cache@v3 - with: - path: | - ~/.vvm - key: compiler-cache - - - name: Setup Python 3.10.4 - uses: actions/setup-python@v4 - with: - python-version: 3.10.4 - - - name: Install Requirements - run: | - pip install poetry==1.5.1 - poetry config virtualenvs.in-project true - poetry install --no-interaction --without dev - - - name: Run Tests - run: | - source .venv/bin/activate - pytest tests/gauge/ --pool-size=2 --pool-type=basic --token-types=plain --decimals=18,18 -n auto diff --git a/.github/tentative_workflows/test_pools_2.yaml b/.github/tentative_workflows/test_pools_2.yaml deleted file mode 100644 index ca96f01b..00000000 --- a/.github/tentative_workflows/test_pools_2.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: test_pools_2 - -on: [pull_request, push] - -env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - WEB3_PROVIDER_URL: ${{ secrets.WEB3_PROVIDER_URL }} - -jobs: - tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Cache Compiler Installations - uses: actions/cache@v3 - with: - path: | - ~/.vvm - key: compiler-cache - - - name: Setup Python 3.10.4 - uses: actions/setup-python@v4 - with: - python-version: 3.10.4 - - - name: Install Requirements - run: | - pip install poetry==1.5.1 - poetry config virtualenvs.in-project true - poetry install --no-interaction --without dev - - - name: Run All Token Tests 18,18 - run: | - source .venv/bin/activate - pytest tests/pools/ --pool-size=2 -n auto - - - name: Run Plain Tests 18,6 - run: | - source .venv/bin/activate - pytest tests/pools/ --pool-size=2 --pool-type=basic --token-types=plain --decimals=18,6 -n auto diff --git a/.github/tentative_workflows/test_token.yaml b/.github/tentative_workflows/test_token.yaml deleted file mode 100644 index 49bd91fe..00000000 --- a/.github/tentative_workflows/test_token.yaml +++ /dev/null @@ -1,35 +0,0 @@ -name: test_token - -on: [pull_request, push] - -env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - -jobs: - tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Cache Compiler Installations - uses: actions/cache@v3 - with: - path: | - ~/.vvm - key: compiler-cache - - - name: Setup Python 3.10.4 - uses: actions/setup-python@v4 - with: - python-version: 3.10.4 - - - name: Install Requirements - run: | - pip install poetry==1.5.1 - poetry config virtualenvs.in-project true - poetry install --no-interaction --without dev - - - name: Run Tests - run: | - source .venv/bin/activate - pytest tests/test_token.py --token-types=plain -n auto diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 00000000..17ff5afd --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,63 @@ +name: CI + +on: [push] + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup Python 3.10.4 + uses: actions/setup-python@v4 + with: + python-version: 3.10.4 + + - uses: pre-commit/action@v3.0.0 + + tests: + runs-on: ubuntu-latest + timeout-minutes: 120 + strategy: + fail-fast: false + matrix: + name: + - gauge + - pools/exchange + - pools/general + - pools/liquidity + - pools/meta + - pools/oracle + - factory + + steps: + - uses: actions/checkout@v3 + + - name: Cache Compiler Installations + uses: actions/cache@v3 + with: + path: ~/.vvm + key: compiler-cache + + - name: Setup Python 3.10.4 + uses: actions/setup-python@v4 + with: + python-version: 3.10.4 + + - name: Install Requirements + run: | + pip install poetry==1.5.1 + poetry config virtualenvs.in-project true + poetry install --no-interaction --without dev + + - name: Run Tests + env: + WEB3_PROVIDER_URL: ${{ secrets.WEB3_PROVIDER_URL }} + run: | + source .venv/bin/activate + pytest --numprocesses=auto tests/${{ matrix.name }}/ diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml deleted file mode 100644 index a0d59e2c..00000000 --- a/.github/workflows/lint.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: lint - -on: [pull_request, push] - -jobs: - - lint: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Setup Python 3.10.4 - uses: actions/setup-python@v4 - with: - python-version: 3.10.4 - - - uses: pre-commit/action@v3.0.0 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 421b2beb..13b11e6a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,26 +2,28 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - - repo: https://github.com/psf/black - rev: 22.3.0 + - repo: https://github.com/psf/black-pre-commit-mirror + rev: 23.12.0 hooks: - id: black - args: [--line-length=120] - - repo: https://github.com/pycqa/flake8 - rev: 4.0.1 + args: + - --skip-magic-trailing-comma + - --target-version=py310 + - repo: https://github.com/PyCQA/flake8 + rev: 6.1.0 hooks: - id: flake8 - args: [--max-line-length=120] - - repo: https://github.com/pycqa/isort - rev: 5.12.0 + - repo: https://github.com/PyCQA/isort + rev: 5.13.2 hooks: - id: isort - args: ["--profile", "black", --line-length=120] + # profile and line-length to avoid clashes with black + args: ["--profile=black", "--line-length=88"] default_language_version: - python: python3.10.4 + python: python3.10 diff --git a/README.MD b/README.md similarity index 67% rename from README.MD rename to README.md index bb547c48..61d428f0 100644 --- a/README.MD +++ b/README.md @@ -13,7 +13,7 @@ For a full list of deployments, please check: [The deployment script](scripts/de The metapool factory has several core components: - [`Factory`](contracts/main/CurveStableSwapFactoryNG.vy) is the main contract used to deploy new metapools. It also acts a registry for finding the deployed pools and querying information about them. -- New pools are deployed via blueprints. The [implementation contract](contracts/main/CurveStableSwapNG.vy) targetted by the proxy is determined according to the base pool. +- New pools are deployed via blueprints. The [implementation contract](contracts/main/CurveStableSwapNG.vy) targeted by the proxy is determined according to the base pool. See the [documentation](https://docs.curve.fi) for more detailed information. @@ -28,14 +28,6 @@ pip install poetry==1.5.1 poetry install ``` -### Paramaters - -- `--pool-size` - size of pool (N_COINS), available parameters: `[2]` -- `--pool-type` - type of pool, available parameters: `[basic,meta]` -- `--token-types` - token types to test against(divided by comma), available parameters: `[plain,eth,oracle,rebasing]` -- `--decimals` - token decimals (divided by comma), default `18,18` -- `--return-types` - types of .transfer() returns to test against (divided by comma), default `revert,False,None` - ### Type of tests Testing gauge @@ -47,13 +39,13 @@ pytest tests/gauge/ Testing factory ```shell -pytest tests/test_factory.py +pytest tests/factory/ ``` Testing swap is ERC20 ```shell -pytest tests/test_token.py +pytest tests/token/ ``` Testing swaps diff --git a/contracts/main/MetaZapNG.vy b/contracts/main/MetaZapNG.vy new file mode 100644 index 00000000..f3202b78 --- /dev/null +++ b/contracts/main/MetaZapNG.vy @@ -0,0 +1,439 @@ +# pragma version 0.3.10 +""" +@title MetaZapNG +@author Curve.Fi +@license Copyright (c) Curve.Fi, 2021 - all rights reserved +@notice A generalised zap contract for Stableswap-ng metapools where the base pool + is a Stableswap-ng implementation as well. +@dev Contract assumes Metapools have 2 coins. +""" + +interface ERC20: + def transfer(receiver: address, amount: uint256): nonpayable + def transferFrom(_sender: address, receiver: address, amount: uint256): nonpayable + def approve(spender: address, amount: uint256): nonpayable + def decimals() -> uint256: view + def balanceOf(owner: address) -> uint256: view + +interface StableSwapMetaNG: + def add_liquidity( + amounts: uint256[META_N_COINS], + min_mint_amount: uint256, + receiver: address + ) -> uint256: nonpayable + def remove_liquidity( + amount: uint256, + min_amounts: uint256[META_N_COINS] + ) -> uint256[META_N_COINS]: nonpayable + def remove_liquidity_one_coin( + token_amount: uint256, + i: int128, + min_amount: uint256, + receiver: address + ) -> uint256: nonpayable + def remove_liquidity_imbalance( + amounts: uint256[META_N_COINS], + max_burn_amount: uint256 + ) -> uint256: nonpayable + def calc_withdraw_one_coin(token_amount: uint256, i: int128) -> uint256: view + def calc_token_amount(amounts: uint256[META_N_COINS], deposit: bool) -> uint256: view + def coins(i: uint256) -> address: view + def BASE_POOL() -> address: view + def BASE_POOL_IS_NG() -> bool: view + +interface StableSwapNG: + def N_COINS() -> uint256: view + def add_liquidity( + amounts: DynArray[uint256, MAX_COINS], + min_mint_amount: uint256 + ) -> uint256: nonpayable + def remove_liquidity( + amount: uint256, + min_amounts: DynArray[uint256, MAX_COINS] + ) -> DynArray[uint256, MAX_COINS]: nonpayable + def remove_liquidity_one_coin( + token_amount: uint256, + i: int128, + min_amount: uint256 + ) -> uint256: nonpayable + def remove_liquidity_imbalance( + amounts: DynArray[uint256, MAX_COINS], + max_burn_amount: uint256 + ) -> uint256: nonpayable + def calc_withdraw_one_coin(token_amount: uint256, i: int128) -> uint256: view + def calc_token_amount( + amounts: DynArray[uint256, MAX_COINS], + deposit: bool + ) -> uint256: view + def coins(i: uint256) -> address: view + def fee() -> uint256: view + + +struct BasePool: + pool_address: address + coins: DynArray[address, MAX_COINS] + + +META_N_COINS: constant(uint256) = 2 +MAX_COINS: constant(uint256) = 8 +MAX_ALL_COINS: constant(uint256) = MAX_COINS + 1 +FEE_DENOMINATOR: constant(uint256) = 10 ** 10 +FEE_IMPRECISION: constant(uint256) = 100 * 10 ** 8 # % of the fee + +# coin -> pool -> is approved to transfer? +is_approved: HashMap[address, HashMap[address, bool]] +base_pool_coins_spending_approved: HashMap[address, bool] +base_pool_registry: HashMap[address, BasePool] + + +@internal +@view +def get_coins_from_pool(_pool: address) -> DynArray[address, MAX_COINS]: + n_coins: uint256 = StableSwapNG(_pool).N_COINS() + coins: DynArray[address, MAX_COINS] = empty(DynArray[address, MAX_COINS]) + for i in range(n_coins, bound=MAX_COINS): + coins.append(StableSwapNG(_pool).coins(i)) + return coins + + +@internal +def _approve_pool_to_spend_zap_coins( + pool: address, + coins: DynArray[address, MAX_COINS], +): + for i in range(len(coins), bound=MAX_COINS): + ERC20(coins[i]).approve(pool, max_value(uint256)) + + self.base_pool_coins_spending_approved[pool] = True + + +@internal +@view +def _fetch_base_pool_data(_pool: address) -> (address, DynArray[address, MAX_COINS]): + + base_pool: address = StableSwapMetaNG(_pool).BASE_POOL() + assert base_pool != empty(address) # dev: not a metapool + base_coins: DynArray[address, MAX_COINS] = self.get_coins_from_pool(base_pool) + return base_pool, base_coins + + +@internal +def _base_pool_data(_pool: address) -> (address, DynArray[address, MAX_COINS]): + + base_pool_data: BasePool = self.base_pool_registry[_pool] + if base_pool_data.pool_address == empty(address): + + base_pool: address = empty(address) + base_coins: DynArray[address, MAX_COINS] = empty(DynArray[address, MAX_COINS]) + base_pool, base_coins = self._fetch_base_pool_data(_pool) + + self.base_pool_registry[_pool] = BasePool( + {pool_address: base_pool, coins: base_coins} + ) + return base_pool, base_coins + + return base_pool_data.pool_address, base_pool_data.coins + + + +@view +@external +def calc_token_amount( + _pool: address, + _amounts: DynArray[uint256, MAX_ALL_COINS], + _is_deposit: bool +) -> uint256: + """ + @notice Calculate addition or reduction in token supply from a deposit or withdrawal + @dev This calculation accounts for slippage, but not fees. + Needed to prevent front-running, not for precise calculations! + @param _pool Address of the pool to deposit into + @param _amounts Amount of each underlying coin being deposited + @param _is_deposit set True for deposits, False for withdrawals + @return Expected amount of LP tokens received + """ + meta_amounts: uint256[META_N_COINS] = empty(uint256[META_N_COINS]) + base_amounts: DynArray[uint256, MAX_COINS] = empty(DynArray[uint256, MAX_COINS]) + base_pool: address = empty(address) + base_coins: DynArray[address, MAX_COINS] = empty(DynArray[address, MAX_COINS]) + base_pool, base_coins = self._fetch_base_pool_data(_pool) + base_n_coins: uint256 = len(base_coins) + + meta_amounts[0] = _amounts[0] + for i in range(base_n_coins, bound=MAX_COINS): + base_amounts.append(_amounts[i + META_N_COINS - 1]) + + base_tokens: uint256 = StableSwapNG(base_pool).calc_token_amount(base_amounts, _is_deposit) + meta_amounts[META_N_COINS - 1] = base_tokens + + return StableSwapMetaNG(_pool).calc_token_amount(meta_amounts, _is_deposit) + + +@external +def add_liquidity( + _pool: address, + _deposit_amounts: DynArray[uint256, MAX_ALL_COINS], + _min_mint_amount: uint256, + _receiver: address = msg.sender, +) -> uint256: + """ + @notice Wrap underlying coins and deposit them into `_pool` + @param _pool Address of the pool to deposit into + @param _deposit_amounts List of amounts of underlying coins to deposit + @param _min_mint_amount Minimum amount of LP tokens to mint from the deposit + @param _receiver Address that receives the LP tokens + @return Amount of LP tokens received by depositing + """ + + base_amounts: DynArray[uint256, MAX_COINS] = empty(DynArray[uint256, MAX_COINS]) + deposit_base: bool = False + + # -------------------------- Get base pool data -------------------------- + + base_pool: address = empty(address) + base_coins: DynArray[address, MAX_COINS] = empty(DynArray[address, MAX_COINS]) + base_pool, base_coins = self._base_pool_data(_pool) + n_all_coins: uint256 = len(base_coins) + 1 + + if not self.base_pool_coins_spending_approved[base_pool]: + self._approve_pool_to_spend_zap_coins(base_pool, base_coins) + + # ------------------------ Transfer tokens to Zap ------------------------ + + meta_amounts: uint256[META_N_COINS] = empty(uint256[META_N_COINS]) + + # Transfer meta-token (token in metapool that is not base pool token) if + # any: + if _deposit_amounts[0] != 0: + coin: address = StableSwapMetaNG(_pool).coins(0) + if not self.is_approved[coin][_pool]: + ERC20(coin).approve(_pool, max_value(uint256)) + self.is_approved[coin][_pool] = True + ERC20(coin).transferFrom(msg.sender, self, _deposit_amounts[0]) + meta_amounts[0] = _deposit_amounts[0] + + # Transfer base pool coins (if any): + for i in range(n_all_coins, bound=MAX_ALL_COINS): + + amount: uint256 = _deposit_amounts[i] + base_amounts.append(0) + if i == 0 or amount == 0: + base_amounts.append(0) + continue + + deposit_base = True + base_idx: uint256 = i - 1 + coin: address = base_coins[base_idx] + + ERC20(coin).transferFrom(msg.sender, self, amount) + base_amounts[base_idx] = amount + + # ----------------------- Deposit to the base pool ----------------------- + + if deposit_base: + meta_amounts[META_N_COINS - 1] = StableSwapNG(base_pool).add_liquidity(base_amounts, 0) + if not self.is_approved[base_pool][_pool]: + ERC20(base_pool).approve(_pool, max_value(uint256)) + self.is_approved[base_pool][_pool] = True + + # ----------------------- Deposit to the meta pool ----------------------- + + return StableSwapMetaNG(_pool).add_liquidity( + meta_amounts, + _min_mint_amount, + _receiver + ) + + +@view +@external +def calc_withdraw_one_coin(_pool: address, _token_amount: uint256, i: int128) -> uint256: + """ + @notice Calculate the amount received when withdrawing and unwrapping a single coin + @param _pool Address of the pool to deposit into + @param _token_amount Amount of LP tokens to burn in the withdrawal + @param i Index value of the underlying coin to withdraw + @return Amount of coin received + """ + if i < META_N_COINS - 1: + return StableSwapMetaNG(_pool).calc_withdraw_one_coin(_token_amount, i) + else: + base_pool: address = StableSwapMetaNG(_pool).BASE_POOL() + assert base_pool != empty(address) # dev: not a metapool! + _base_tokens: uint256 = StableSwapMetaNG(_pool).calc_withdraw_one_coin(_token_amount, META_N_COINS - 1) + return StableSwapNG(base_pool).calc_withdraw_one_coin( + _base_tokens, + i - convert(META_N_COINS - 1, int128) + ) + + +@external +def remove_liquidity( + _pool: address, + _burn_amount: uint256, + _min_amounts: DynArray[uint256, MAX_ALL_COINS], + _receiver: address = msg.sender +) -> DynArray[uint256, MAX_ALL_COINS]: + """ + @notice Withdraw and unwrap coins from the pool + @dev Withdrawal amounts are based on current deposit ratios + @param _pool Address of the pool to deposit into + @param _burn_amount Quantity of LP tokens to burn in the withdrawal + @param _min_amounts Minimum amounts of underlying coins to receive + @param _receiver Address that receives the LP tokens + @return List of amounts of underlying coins that were withdrawn + """ + ERC20(_pool).transferFrom(msg.sender, self, _burn_amount) + + base_pool: address = empty(address) + base_coins: DynArray[address, MAX_COINS] = empty(DynArray[address, MAX_COINS]) + base_pool, base_coins = self._base_pool_data(_pool) + base_n_coins: uint256 = len(base_coins) + + min_amounts_base: DynArray[uint256, MAX_COINS] = empty(DynArray[uint256, MAX_COINS]) + amounts: DynArray[uint256, MAX_ALL_COINS] = empty(DynArray[uint256, MAX_ALL_COINS]) + + # Withdraw from meta + meta_received: uint256[META_N_COINS] = StableSwapMetaNG(_pool).remove_liquidity( + _burn_amount, + [_min_amounts[0], convert(0, uint256)] + ) + + # Withdraw from base + for i in range(base_n_coins, bound=MAX_COINS): + min_amounts_base.append(_min_amounts[i + META_N_COINS - 1]) + StableSwapNG(base_pool).remove_liquidity(meta_received[1], min_amounts_base) + + # Transfer all coins out + coin: address = StableSwapMetaNG(_pool).coins(0) + ERC20(coin).transfer(_receiver, meta_received[0]) + amounts.append(meta_received[0]) + + for i in range(base_n_coins + 1, bound=MAX_ALL_COINS): + + if i == 0: + continue + + coin = base_coins[i-1] + amounts.append(ERC20(coin).balanceOf(self)) + + ERC20(coin).transfer(_receiver, amounts[i]) + + return amounts + + +@external +def remove_liquidity_one_coin( + _pool: address, + _burn_amount: uint256, + i: int128, + _min_amount: uint256, + _receiver: address=msg.sender +) -> uint256: + """ + @notice Withdraw and unwrap a single coin from the pool + @param _pool Address of the pool to deposit into + @param _burn_amount Amount of LP tokens to burn in the withdrawal + @param i Index value of the coin to withdraw + @param _min_amount Minimum amount of underlying coin to receive + @param _receiver Address that receives the LP tokens + @return Amount of underlying coin received + """ + ERC20(_pool).transferFrom(msg.sender, self, _burn_amount) + + coin_amount: uint256 = 0 + if i == 0: + coin_amount = StableSwapMetaNG(_pool).remove_liquidity_one_coin( + _burn_amount, i, _min_amount, _receiver + ) + else: + base_pool: address = empty(address) + base_coins: DynArray[address, MAX_COINS] = empty(DynArray[address, MAX_COINS]) + base_pool, base_coins = self._base_pool_data(_pool) + base_n_coins: uint256 = len(base_coins) + + coin: address = base_coins[i - convert(META_N_COINS - 1, int128)] + # Withdraw a base pool coin + coin_amount = StableSwapMetaNG(_pool).remove_liquidity_one_coin( + _burn_amount, convert(META_N_COINS - 1, int128), 0, self + ) + coin_amount = StableSwapNG(base_pool).remove_liquidity_one_coin( + coin_amount, i - convert(META_N_COINS - 1, int128), _min_amount + ) + ERC20(coin).transfer(_receiver, coin_amount) + + return coin_amount + + +@external +def remove_liquidity_imbalance( + _pool: address, + _amounts: DynArray[uint256, MAX_ALL_COINS], + _max_burn_amount: uint256, + _receiver: address=msg.sender +) -> uint256: + """ + @notice Withdraw coins from the pool in an imbalanced amount + @param _pool Address of the pool to deposit into + @param _amounts List of amounts of underlying coins to withdraw + @param _max_burn_amount Maximum amount of LP token to burn in the withdrawal + @param _receiver Address that receives the LP tokens + @return Actual amount of the LP token burned in the withdrawal + """ + + base_pool: address = empty(address) + base_coins: DynArray[address, MAX_COINS] = empty(DynArray[address, MAX_COINS]) + base_pool, base_coins = self._base_pool_data(_pool) + base_n_coins: uint256 = len(base_coins) + + fee: uint256 = StableSwapNG(base_pool).fee() * base_n_coins / (4 * (base_n_coins - 1)) + fee += fee * FEE_IMPRECISION / FEE_DENOMINATOR # Overcharge to account for imprecision + + # Transfer the LP token in + ERC20(_pool).transferFrom(msg.sender, self, _max_burn_amount) + + withdraw_base: bool = False + amounts_base: DynArray[uint256, MAX_COINS] = empty(DynArray[uint256, MAX_COINS]) + amounts_meta: uint256[META_N_COINS] = [_amounts[0], 0] + + # determine amounts to withdraw from base pool + for i in range(base_n_coins, bound=MAX_COINS): + amount: uint256 = _amounts[META_N_COINS - 1 + i] + if amount != 0: + amounts_base.append(amount) + withdraw_base = True + else: + amounts_base.append(0) + + # determine amounts to withdraw from metapool + if withdraw_base: + amounts_meta[1] = StableSwapNG(base_pool).calc_token_amount(amounts_base, False) + amounts_meta[1] += amounts_meta[1] * fee / FEE_DENOMINATOR + 1 + + # withdraw from metapool and return the remaining LP tokens + burn_amount: uint256 = StableSwapMetaNG(_pool).remove_liquidity_imbalance(amounts_meta, _max_burn_amount) + ERC20(_pool).transfer(msg.sender, _max_burn_amount - burn_amount) + + # withdraw from base pool + if withdraw_base: + StableSwapNG(base_pool).remove_liquidity_imbalance(amounts_base, amounts_meta[1]) + coin: address = base_pool + leftover: uint256 = ERC20(coin).balanceOf(self) + + if leftover > 0: + # if some base pool LP tokens remain, re-deposit them for the caller + if not self.is_approved[coin][_pool]: + ERC20(coin).approve(_pool, MAX_UINT256) + self.is_approved[coin][_pool] = True + burn_amount -= StableSwapMetaNG(_pool).add_liquidity([convert(0, uint256), leftover], 0, msg.sender) + + # transfer withdrawn base pool tokens to caller + for i in range(base_n_coins, bound=MAX_COINS): + ERC20(base_coins[i]).transfer(_receiver, amounts_base[i]) + + # transfer withdrawn metapool tokens to caller + if _amounts[0] > 0: + coin: address = StableSwapMetaNG(_pool).coins(0) + ERC20(coin).transfer(_receiver, _amounts[0]) + + return burn_amount diff --git a/contracts/mocks/CallbackSwap.vy b/contracts/mocks/CallbackSwap.vy index d19c21b4..96a2e099 100644 --- a/contracts/mocks/CallbackSwap.vy +++ b/contracts/mocks/CallbackSwap.vy @@ -1,4 +1,4 @@ -# @version ^0.3.9 +# pragma version 0.3.10 """ @title CurveExchangeWithoutApproval @author fiddyresearch.eth diff --git a/contracts/mocks/CurvePool.vy b/contracts/mocks/CurvePool.vy index 22a7bde1..b0424323 100644 --- a/contracts/mocks/CurvePool.vy +++ b/contracts/mocks/CurvePool.vy @@ -1,4 +1,4 @@ -# @version ^0.3.9 +# pragma version 0.3.10 """ @title StableSwap @author Curve.Fi diff --git a/contracts/mocks/CurveTokenV3.vy b/contracts/mocks/CurveTokenV3.vy index 0af3dc1b..a1999cfb 100644 --- a/contracts/mocks/CurveTokenV3.vy +++ b/contracts/mocks/CurveTokenV3.vy @@ -1,4 +1,4 @@ -# @version ^0.3.9 +# pragma version 0.3.10 """ @title Curve LP Token @author Curve.Fi diff --git a/contracts/mocks/ERC20.vy b/contracts/mocks/ERC20.vy index efeee386..614781ee 100644 --- a/contracts/mocks/ERC20.vy +++ b/contracts/mocks/ERC20.vy @@ -1,4 +1,4 @@ -# @version ^0.3.9 +# pragma version 0.3.10 """ @notice Mock ERC20 for testing diff --git a/contracts/mocks/ERC20Oracle.vy b/contracts/mocks/ERC20Oracle.vy index 24e62b6e..69025954 100644 --- a/contracts/mocks/ERC20Oracle.vy +++ b/contracts/mocks/ERC20Oracle.vy @@ -1,4 +1,4 @@ -# @version ^0.3.9 +# pragma version 0.3.10 """ @notice Mock ERC20 with oracle diff --git a/contracts/mocks/ERC20Rebasing.vy b/contracts/mocks/ERC20Rebasing.vy index 232b9178..14e9579c 100644 --- a/contracts/mocks/ERC20Rebasing.vy +++ b/contracts/mocks/ERC20Rebasing.vy @@ -1,4 +1,4 @@ -# @version ^0.3.9 +# pragma version 0.3.10 """ @notice Rebasing ERC20 mock with rebase by 1% on every transfer diff --git a/contracts/mocks/ERC20RebasingConditional.vy b/contracts/mocks/ERC20RebasingConditional.vy index 77ca22d4..50ff3042 100644 --- a/contracts/mocks/ERC20RebasingConditional.vy +++ b/contracts/mocks/ERC20RebasingConditional.vy @@ -1,4 +1,4 @@ -# @version ^0.3.9 +# pragma version 0.3.10 """ @notice Rebasing ERC20 mock with rebase by 1% on every transfer diff --git a/contracts/mocks/ERC4626.vy b/contracts/mocks/ERC4626.vy index 52f2d657..1e596cdc 100644 --- a/contracts/mocks/ERC4626.vy +++ b/contracts/mocks/ERC4626.vy @@ -1,4 +1,4 @@ -# @version 0.3.10 +# pragma version 0.3.10 # From: https://github.com/fubuloubu/ERC4626/blob/main/contracts/VyperVault.vy from vyper.interfaces import ERC20 from vyper.interfaces import ERC20Detailed diff --git a/contracts/mocks/Zap.vy b/contracts/mocks/Zap.vy index b245916e..8fb1670b 100644 --- a/contracts/mocks/Zap.vy +++ b/contracts/mocks/Zap.vy @@ -1,4 +1,4 @@ -# @version 0.3.10 +# pragma version 0.3.10 """ @title "Zap" Depositer for permissionless USD metapools @author Curve.Fi diff --git a/poetry.lock b/poetry.lock index 56d0244a..58e38c0f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,191 +1,171 @@ # This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. -[[package]] -name = "appnope" -version = "0.1.3" -description = "Disable App Nap on macOS >= 10.9" -optional = false -python-versions = "*" -files = [ - {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, - {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, -] - [[package]] name = "asttokens" -version = "2.4.0" +version = "2.4.1" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" files = [ - {file = "asttokens-2.4.0-py2.py3-none-any.whl", hash = "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69"}, - {file = "asttokens-2.4.0.tar.gz", hash = "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e"}, + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, ] [package.dependencies] six = ">=1.12.0" [package.extras] -test = ["astroid", "pytest"] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] [[package]] name = "attrs" -version = "23.1.0" +version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] +dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] - -[[package]] -name = "backcall" -version = "0.2.0" -description = "Specifications for callback functions passed in to an API" -optional = false -python-versions = "*" -files = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "bitarray" -version = "2.8.2" +version = "2.9.2" description = "efficient arrays of booleans -- C extension" optional = false python-versions = "*" files = [ - {file = "bitarray-2.8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:525eda30469522cd840a11ba866d0616c132f6c4be8966a297d7545e97fcb822"}, - {file = "bitarray-2.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c3d9730341c825eb167ca06c9dddf6ad4d1b4e71ea7da73cc8c5139fcb5e14ca"}, - {file = "bitarray-2.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad8f8c39c8df184e346184699783f105755003662f0dbe1233d9d9849650ab5f"}, - {file = "bitarray-2.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8d08330d250df47088c13683322083afbdfafdc31df205616506d6b9f068f"}, - {file = "bitarray-2.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56f19ccba8a6ddf1382b0fb4fb8d4e1330e4a1b148e5d198f0981ba2a97c3492"}, - {file = "bitarray-2.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4db2e0f58153a376d9a14873e342d507ca32640640284cddf3c1e74a65929477"}, - {file = "bitarray-2.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b3c27aeea1752f0c1df1e29115e4b6f0249173d71e53c5f7e2c821706f028b"}, - {file = "bitarray-2.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef23f62b3abd287cf368341540ef2a81c86b48de9d488e182e63fe24ac165538"}, - {file = "bitarray-2.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6d79fd3c58a4dc71ffd0fc55982a9a2079fe94c76ccff2777092f6107d6a049a"}, - {file = "bitarray-2.8.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8528c59d3d3df6618777892b60435022d8917de9ea32933d439c7ffd24437237"}, - {file = "bitarray-2.8.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c35bb5fe018fd9c42be3c28e74dc7dcfae471c3c6689679dbd0bd1d6dc0f51b7"}, - {file = "bitarray-2.8.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:232e8faa8e624f3eb0552a636ebe745cee00480e0e56ad62f17808d281838f2e"}, - {file = "bitarray-2.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:945e97ad2bbf7885426f39641a735a31fd4ca2e84e4d0cd271d9880372d6eae1"}, - {file = "bitarray-2.8.2-cp310-cp310-win32.whl", hash = "sha256:88c2d427ab1b20f220c1d53171b0691faa8f0a219367d84e859f1001e90ceefc"}, - {file = "bitarray-2.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:f7c5745e0f96c2c16c03c7540dbe26f3b62ddee63059be0a014156933f054024"}, - {file = "bitarray-2.8.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a610426251d1340baa4d8b7942d2cbfe6a1e20b92c66817ab582e0d341185ab5"}, - {file = "bitarray-2.8.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:599b04b04eb1b5b964a35986bea2bc4381145836fe550cc33c40a796b855b985"}, - {file = "bitarray-2.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9014660472f2080d550157164cc5f9376245a34a0ab877b82b95c1f894af5b28"}, - {file = "bitarray-2.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:532d63c54159f7e0fb520e2f72ef596493bc43810eaa75fac7a188e898ab593b"}, - {file = "bitarray-2.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad1563f11dd70cb1684cfe841e4cf7f35d4f65769de21d12b72cf773a7932615"}, - {file = "bitarray-2.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e456150af62ee1f24a0c9976947629bfb80d80b4fbd37aa901cf794db6ba9b0"}, - {file = "bitarray-2.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cc29909e4cef05d5e49f5d77ace1dc49311c7791734a048b690521c76b4b7a0"}, - {file = "bitarray-2.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:608385f07a4b0391d4982d1efb83ad70920cd8ca495a7868e44d2a4511cbf84e"}, - {file = "bitarray-2.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2baf7ec353fa64917045b3efe26e7c12ce0d7b4d120c3773a612dce54f91585"}, - {file = "bitarray-2.8.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2c39d1cb04fc277701de6fe2119cc71facc4aff2ca0414b2e326aec337fa1ab4"}, - {file = "bitarray-2.8.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:3caf4ca668854bb23db4b65af0068238677b5791bcc45694bf8990f3e26e85c9"}, - {file = "bitarray-2.8.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4bbfe4474d3470c724e283bd1fe8ee9ab3cb6a4c378112926f45d41e326a7622"}, - {file = "bitarray-2.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb941981676dc7859d53199a10a33ca56a3146cce6a45bc6ad70572c1147157d"}, - {file = "bitarray-2.8.2-cp311-cp311-win32.whl", hash = "sha256:e8963d7ac292f41654fa7cbc1a34efdb09e5a42399b2e3689c3fd5b8b4e0fe16"}, - {file = "bitarray-2.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:ee779a291330287b341044635fce2979176d113b0dcce0308dc5d62da7951eec"}, - {file = "bitarray-2.8.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:05d84765bbfd0aa10890c765c56c917c237987325c4e327f3c0febbfc34365c8"}, - {file = "bitarray-2.8.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c7b7be4bff27d7ce6a81d3993755371b5f5b42436afa151868e8fd599acbab19"}, - {file = "bitarray-2.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c3d51ab9f3d5b9a10295abe480c50bf74ee5bf3d984c4cee77e493e575acc869"}, - {file = "bitarray-2.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00bad63ef6f9d22ba36b01b89167176a451ea22a916d1dfa77d73e0298f1d1f9"}, - {file = "bitarray-2.8.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:225e19d37b234d4d721557434b7d5590cd63b6342492b689e2d694d44d7cc537"}, - {file = "bitarray-2.8.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7e3ab9870c496e5a058436bf4d96ed111ca6154c8ef8147b70c44c188d6fb2c"}, - {file = "bitarray-2.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff3e182c766cd6f302e99e0d8e44927d533356e9d6ac93fcd09987ebead467aa"}, - {file = "bitarray-2.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7bb559b68eb9cb3c4f867eb9fb39a696c4da70a41fad37b410bd0c7b426a8ce"}, - {file = "bitarray-2.8.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:97e658a3793478d6bca684f47f29f62542312683687bc045dc3cb588160e74b3"}, - {file = "bitarray-2.8.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:dd351b8fbc77c2e2ebc3eeadc0cf72bd5024a43bef5a847697e2b076d1201636"}, - {file = "bitarray-2.8.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:280809e56a7098f48165ce134222098e4cfe7084b10d69bbc31367942e541dfd"}, - {file = "bitarray-2.8.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14bc38ced7edffff25ee748c1eabc530624c9af68f86322b030b11b7918b966f"}, - {file = "bitarray-2.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:de4953b6b1e19dabd23767bd1f83f1cf73978372189dec0e2dd8b3d6971100d6"}, - {file = "bitarray-2.8.2-cp312-cp312-win32.whl", hash = "sha256:99196b4730d887a4bc578f05039b55dc57b131c81b5a5e03efa619b587bdf293"}, - {file = "bitarray-2.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:215a5bf8fdcbed700cc8782d4044e1f036606d5c321710d83e8da6d0fdfe07d5"}, - {file = "bitarray-2.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e9c54136c9fab2cefe9801e336b8a3aa7299bcfe7f387379cc6394ad1d5a484b"}, - {file = "bitarray-2.8.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08ad70c1555d9622cecd8f1b132a5341d183a9161aba93cc9739bbaabe4220b0"}, - {file = "bitarray-2.8.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:384be6b7df8fb6a93ddd88d4184094f2ba4f1d07c30dcd4ae164d185d31a2af6"}, - {file = "bitarray-2.8.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd2a098250c683d248a6490ac437ed56f7164d2151572231bd26c76bfe111b11"}, - {file = "bitarray-2.8.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6ae5c18b9a70cb0ae576a8a3c8a9a0659356c016b49cc6b263dd987d344f30d"}, - {file = "bitarray-2.8.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:188f5780f1cfbeba0c3ddb1aa3fa0415ab1a8aa04e9e89f70ad5403197013437"}, - {file = "bitarray-2.8.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:5f2a96c5b40727bc21a695d3a106f49e88572fa11427bf2193cabd99e624c901"}, - {file = "bitarray-2.8.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:b6df948da34b5fb949698092573d798c76c54f2f2188db59276d599075f9ed04"}, - {file = "bitarray-2.8.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:a1f00c328b8dae1828844bac019dfe425d10a2043cc70e2f967224c5392d19ad"}, - {file = "bitarray-2.8.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:7965108069f9731306a882872c23ad4f5a8531668e82b27932a19814c52a8dd8"}, - {file = "bitarray-2.8.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:420aa610fe392c4ee700e474673276bb4f3c4f091d001f58b1f018bf650840c1"}, - {file = "bitarray-2.8.2-cp36-cp36m-win32.whl", hash = "sha256:b85929db81105c06e8292c05cac093068e86464555c628c03f99c9f8090d68d4"}, - {file = "bitarray-2.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:cba09dfd3aea2addc994eb21a861c3cea2d68141bb7ebe68b0e94c73405540f9"}, - {file = "bitarray-2.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:172169099797f1ec469b0aadb00c653193a74757f99312c9c17dc1a18d23d972"}, - {file = "bitarray-2.8.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:351a4fed240728dcc96966e0c4cfd3dce870525377a1cb5afac8e5cfe116ff7b"}, - {file = "bitarray-2.8.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff31bef13fd278446b6d1969a46db9f02c36fd905f3e75878f0fe17271f7d897"}, - {file = "bitarray-2.8.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb8b727cd9ddff848c5f73e65470abb110f026beab403bcebbd74e7439b9bd8f"}, - {file = "bitarray-2.8.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d1356c86eefbde3fe8a3c39fb81bbc8b16acc8e442e191408042e8b1d6904e3"}, - {file = "bitarray-2.8.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7706336bd15acf4e42300579e42bef742c01a4eb202998f6c20c443a2ce5fd60"}, - {file = "bitarray-2.8.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a4b43949477dc2b0d3e1d8b7c413ed74f515cef01954cdcc3fb1e2dcc49f2aff"}, - {file = "bitarray-2.8.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:06d9de5db244c6e45a5318713367765de0a57d82ad616869a004a710a95541e9"}, - {file = "bitarray-2.8.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:5569c8314335e92570c471d60b4b03eb2a4467864805a560d133d24b27b3961a"}, - {file = "bitarray-2.8.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:76a4faef4c31953aa7b9ebe00d162f7ce9bc03fc8d423ab2dc690a11d7520a8e"}, - {file = "bitarray-2.8.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1474db8c4297026e1daa1699e70e25e56dff91104fe025b1a9804332f2737604"}, - {file = "bitarray-2.8.2-cp37-cp37m-win32.whl", hash = "sha256:85b504f233f0484e9a74df4f286a9ae56fbbe2a648c45726761cf7b6f072cdc8"}, - {file = "bitarray-2.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:3dde123ce85d1ba99d9bdf44b1b3174fa22bc8fb10004e0d72bb661a0444c1a9"}, - {file = "bitarray-2.8.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:23fae6a5a1403d16592b8823d5dea93f738c6e217a1e1bb0eefad242fb03d47f"}, - {file = "bitarray-2.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c44b3022115eb1697315bc51aeadbade1a19d7188bcda66c52d91209cf2963ca"}, - {file = "bitarray-2.8.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fea9354b7169810e2bdd6f3265ff128b564a25d38479b9ad0a9c5776e4fd0cfc"}, - {file = "bitarray-2.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f699bf2cb223aeec04a106003bd2bf8a4fc6d4c5eddf79cacecb6b267657ac5"}, - {file = "bitarray-2.8.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:462c9425fbc5315cbc20a72ca62558e5545bb0f6dc9355e2fa96fa747e9b1a80"}, - {file = "bitarray-2.8.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c8716b4c45fb128cd4da143749e276f150ecb0acb711f4969d7e7ebc9b2a675"}, - {file = "bitarray-2.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79fde5b27e35aedd958f5fb58ebabce47d7eddae5a5e3774088c30c9610195ef"}, - {file = "bitarray-2.8.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abf2593b91e36f1cb1c40ac895993c7d2eb30d3f1cb0954a80e5f13697b6b69"}, - {file = "bitarray-2.8.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ab2e03dd140ab93b91f94a785d1cd6082d5ab53ab6ec958726efa0ad17f7b87a"}, - {file = "bitarray-2.8.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9e895cc3e5ffee269dd9866097e227a68022ef2b78d627a6ed737534d0c88c14"}, - {file = "bitarray-2.8.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:0bbeb7120ec1a9b26ce423e74cad7b414cea9e35f8e05599e3b3dceb87f4d1b6"}, - {file = "bitarray-2.8.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:51d45d56be14b69720d11a8c61e101d86a65dc8a3a9f356bbe4d98cf4f3c5617"}, - {file = "bitarray-2.8.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:726a598e34657772e5f131115741ea8709e9b55fa35d63c4717bc16b2a737d38"}, - {file = "bitarray-2.8.2-cp38-cp38-win32.whl", hash = "sha256:ab87c4c50d65932788d058adbbd28a209144523ffacbab81dd41582ffce26af9"}, - {file = "bitarray-2.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:316147fb62c810a7667277e5ae7bb75b2871c32d2c398aeb4503cbd4cf3315e7"}, - {file = "bitarray-2.8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:36bdde1aba78e4a3a6ce5cbebd0a6bc967b0c3fbd8bd99a197dcc17d654f423c"}, - {file = "bitarray-2.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:932f7b77750dff7140522dc97dfd94533a599ef1c5d0be3733f556fd44a68821"}, - {file = "bitarray-2.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5819b95d0ccce864066f062d2329363ae8a64b9c3d076d039c75ffc9204c2a12"}, - {file = "bitarray-2.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c28b52e59a5e6aa00a929b35b04473bd479a74237ab1170c573c49e8aca61fe"}, - {file = "bitarray-2.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ecdd528268478efeb78ed0132b01104bda6cd8f10c8a57708fc87b1add77e4d"}, - {file = "bitarray-2.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f6f245d4a5e707d48274f38551b654a36db4fb83437c98be00d2019263aa364"}, - {file = "bitarray-2.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b088f06d9e2f523683ae363e227173ac454dbb56c938c6d42791fdd78bad8da7"}, - {file = "bitarray-2.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e883919cea8e446c5c49717a7ce5c93a016a02b9429b81d64b9ab1d80fc12e42"}, - {file = "bitarray-2.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:09d729420b8edc4d8a23a518ae4553074a0054d0441c1a461b425c2f033fab5e"}, - {file = "bitarray-2.8.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d0d0923087fe1f2d85daa68463d221e90b4b8ed0356480c887eea90b2a2cc7ee"}, - {file = "bitarray-2.8.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:70cebcf9bc345ac1e034fa781eac3619323eaf87f7bbe26f0e28850beb6f5634"}, - {file = "bitarray-2.8.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:890355bf6ba3dc04b5a23d1328eb1f6062165e6262197cebc9acfebdcb23144c"}, - {file = "bitarray-2.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f0b54b95e39036c116ffc057b3f56f6084ce88822de3d5d1f57fa38554ccf5c1"}, - {file = "bitarray-2.8.2-cp39-cp39-win32.whl", hash = "sha256:b499d93fa31a73e31ee62f2cbe07e4df833fd7151734b8f07c48ffe3e4547ec5"}, - {file = "bitarray-2.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:b007aaf5810c708c5a2778e371aa546d7084e4e9f82f65865b2ce5a182376f42"}, - {file = "bitarray-2.8.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1b734b074a09b1b2e1de7df423565412d9213faefa8ca422f32be756b189f729"}, - {file = "bitarray-2.8.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd074b06be9484040acb4c2c0462c4d19a43e377716be7ba10440f51a57bb98c"}, - {file = "bitarray-2.8.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e678696bb613f0344b79be385747aae705b327a9a32ace45a353dd16497bc719"}, - {file = "bitarray-2.8.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb337ffa10824fa2025c4b1c06a2d809dbed4a4bf9e3ffb262676d084c4e0c50"}, - {file = "bitarray-2.8.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2b3c7aa2c9a6533dc7234d2a303efdcb9df3f4ac4d0919ec1caf568868f12a0a"}, - {file = "bitarray-2.8.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e6765c47b487341837b3731cca3c8033b971ee082f6ab41cb430aa3447686eec"}, - {file = "bitarray-2.8.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb8566b535bc4ebb26247d6f636a27bb0038bc93fa7e55121628f5cd6b0906ac"}, - {file = "bitarray-2.8.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56764825f64ab983d32b8c1d4ee483f415f2559e59388ba266a9fcafc44305bf"}, - {file = "bitarray-2.8.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f45f7d58c399e90ee3bddff4f3e2f53ff95c948b2d43de304266153ebd1d778"}, - {file = "bitarray-2.8.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:095851409e0db75b1416c8c3e24957135d5a2a206790578e43739e92a00c17c4"}, - {file = "bitarray-2.8.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8bb60d5a948f00901da1d7e4953189259b3c7ef79391fecd6f18db3f48a036fe"}, - {file = "bitarray-2.8.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b2dc483ada55ef35990b67dc0e7a779f0b2ce79d156e452dc8b835b03c0dca9"}, - {file = "bitarray-2.8.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a35e308c23f039064600108fc1c8416bd102bc3cf3a6915761a9f7c801237e0"}, - {file = "bitarray-2.8.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa49f6cfcae4305d8cff028dc9c9a881189a38f7ca43c085aef894c58cb6fbde"}, - {file = "bitarray-2.8.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:111bf9913ebee4630e2cb43b61d0abb39813b231262b114e5268cd6a405a22b9"}, - {file = "bitarray-2.8.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b71d82e3f001bcb53463023f7f37e223fff56cf048f577c6d85597db94770f10"}, - {file = "bitarray-2.8.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:440c537fdf2eaee7fdd41fb1dce5701c490c1964fdb74225b10b49a7c45bc7b4"}, - {file = "bitarray-2.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c384c49ce52b82d5b0355000b8aeb7e3a7654997916c1e6fd9d29697edda1076"}, - {file = "bitarray-2.8.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27428d7b0e706307d0c697f81599e7af4f52e5873ea6bc269eae3604b16b81fe"}, - {file = "bitarray-2.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4963982d5da0825768f9a80760a8560c3e4cf711a9a7ea06ff9bcb7bd250b131"}, - {file = "bitarray-2.8.2.tar.gz", hash = "sha256:f90b2f44b5b23364d5fbade2c34652e15b1fcfe813c46f828e008f68a709160f"}, + {file = "bitarray-2.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:917905de565d9576eb20f53c797c15ba88b9f4f19728acabec8d01eee1d3756a"}, + {file = "bitarray-2.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b35bfcb08b7693ab4bf9059111a6e9f14e07d57ac93cd967c420db58ab9b71e1"}, + {file = "bitarray-2.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ea1923d2e7880f9e1959e035da661767b5a2e16a45dfd57d6aa831e8b65ee1bf"}, + {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0b63a565e8a311cc8348ff1262d5784df0f79d64031d546411afd5dd7ef67d"}, + {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf0620da2b81946d28c0b16f3e3704d38e9837d85ee4f0652816e2609aaa4fed"}, + {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79a9b8b05f2876c7195a2b698c47528e86a73c61ea203394ff8e7a4434bda5c8"}, + {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:345c76b349ff145549652436235c5532e5bfe9db690db6f0a6ad301c62b9ef21"}, + {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e2936f090bf3f4d1771f44f9077ebccdbc0415d2b598d51a969afcb519df505"}, + {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f9346e98fc2abcef90b942973087e2462af6d3e3710e82938078d3493f7fef52"}, + {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e6ec283d4741befb86e8c3ea2e9ac1d17416c956d392107e45263e736954b1f7"}, + {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:962892646599529917ef26266091e4cb3077c88b93c3833a909d68dcc971c4e3"}, + {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e8da5355d7d75a52df5b84750989e34e39919ec7e59fafc4c104cc1607ab2d31"}, + {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:603e7d640e54ad764d2b4da6b61e126259af84f253a20f512dd10689566e5478"}, + {file = "bitarray-2.9.2-cp310-cp310-win32.whl", hash = "sha256:f00079f8e69d75c2a417de7961a77612bb77ef46c09bc74607d86de4740771ef"}, + {file = "bitarray-2.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:1bb33673e7f7190a65f0a940c1ef63266abdb391f4a3e544a47542d40a81f536"}, + {file = "bitarray-2.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fe71fd4b76380c2772f96f1e53a524da7063645d647a4fcd3b651bdd80ca0f2e"}, + {file = "bitarray-2.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d527172919cdea1e13994a66d9708a80c3d33dedcf2f0548e4925e600fef3a3a"}, + {file = "bitarray-2.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:052c5073bdcaa9dd10628d99d37a2f33ec09364b86dd1f6281e2d9f8d3db3060"}, + {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e064caa55a6ed493aca1eda06f8b3f689778bc780a75e6ad7724642ba5dc62f7"}, + {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:508069a04f658210fdeee85a7a0ca84db4bcc110cbb1d21f692caa13210f24a7"}, + {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4da73ebd537d75fa7bccfc2228fcaedea0803f21dd9d0bf0d3b67fef3c4af294"}, + {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cb378eaa65cd43098f11ff5d27e48ee3b956d2c00d2d6b5bfc2a09fe183be47"}, + {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d14c790b91f6cbcd9b718f88ed737c78939980c69ac8c7f03dd7e60040c12951"}, + {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eea9318293bc0ea6447e9ebfba600a62f3428bea7e9c6d42170ae4f481dbab3"}, + {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b76ffec27c7450b8a334f967366a9ebadaea66ee43f5b530c12861b1a991f503"}, + {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:76b76a07d4ee611405045c6950a1e24c4362b6b44808d4ad6eea75e0dbc59af4"}, + {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c7d16beeaaab15b075990cd26963d6b5b22e8c5becd131781514a00b8bdd04bd"}, + {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60df43e868a615c7e15117a1e1c2e5e11f48f6457280eba6ddf8fbefbec7da99"}, + {file = "bitarray-2.9.2-cp311-cp311-win32.whl", hash = "sha256:e788608ed7767b7b3bbde6d49058bccdf94df0de9ca75d13aa99020cc7e68095"}, + {file = "bitarray-2.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:a23397da092ef0a8cfe729571da64c2fc30ac18243caa82ac7c4f965087506ff"}, + {file = "bitarray-2.9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:90e3a281ffe3897991091b7c46fca38c2675bfd4399ffe79dfeded6c52715436"}, + {file = "bitarray-2.9.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bed637b674db5e6c8a97a4a321e3e4d73e72d50b5c6b29950008a93069cc64cd"}, + {file = "bitarray-2.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e49066d251dbbe4e6e3a5c3937d85b589e40e2669ad0eef41a00f82ec17d844b"}, + {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4344e96642e2211fb3a50558feff682c31563a4c64529a931769d40832ca79"}, + {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aeb60962ec4813c539a59fbd4f383509c7222b62c3fb1faa76b54943a613e33a"}, + {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed0f7982f10581bb16553719e5e8f933e003f5b22f7d25a68bdb30fac630a6ff"}, + {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c71d1cabdeee0cdda4669168618f0e46b7dace207b29da7b63aaa1adc2b54081"}, + {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0ef2d0a6f1502d38d911d25609b44c6cc27bee0a4363dd295df78b075041b60"}, + {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6f71d92f533770fb027388b35b6e11988ab89242b883f48a6fe7202d238c61f8"}, + {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ba0734aa300757c924f3faf8148e1b8c247176a0ac8e16aefdf9c1eb19e868f7"}, + {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:d91406f413ccbf4af6ab5ae7bc78f772a95609f9ddd14123db36ef8c37116d95"}, + {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:87abb7f80c0a042f3fe8e5264da1a2756267450bb602110d5327b8eaff7682e7"}, + {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b558ce85579b51a2e38703877d1e93b7728a7af664dd45a34e833534f0b755d"}, + {file = "bitarray-2.9.2-cp312-cp312-win32.whl", hash = "sha256:dac2399ee2889fbdd3472bfc2ede74c34cceb1ccf29a339964281a16eb1d3188"}, + {file = "bitarray-2.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:48a30d718d1a6dfc22a49547450107abe8f4afdf2abdcbe76eb9ed88edc49498"}, + {file = "bitarray-2.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2c6be1b651fad8f3adb7a5aa12c65b612cd9b89530969af941844ae680f7d981"}, + {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5b399ae6ab975257ec359f03b48fc00b1c1cd109471e41903548469b8feae5c"}, + {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b3543c8a1cb286ad105f11c25d8d0f712f41c5c55f90be39f0e5a1376c7d0b0"}, + {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03adaacb79e2fb8f483ab3a67665eec53bb3fd0cd5dbd7358741aef124688db3"}, + {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ae5b0657380d2581e13e46864d147a52c1e2bbac9f59b59c576e42fa7d10cf0"}, + {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c1f4bf6ea8eb9d7f30808c2e9894237a96650adfecbf5f3643862dc5982f89e"}, + {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a8873089be2aa15494c0f81af1209f6e1237d762c5065bc4766c1b84321e1b50"}, + {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:677e67f50e2559efc677a4366707070933ad5418b8347a603a49a070890b19bc"}, + {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:a620d8ce4ea2f1c73c6b6b1399e14cb68c6915e2be3fad5808c2998ed55b4acf"}, + {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:64115ccabbdbe279c24c367b629c6b1d3da9ed36c7420129e27c338a3971bfee"}, + {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5d6fb422772e75385b76ad1c52f45a68bd4efafd8be8d0061c11877be74c4d43"}, + {file = "bitarray-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:852e202875dd6dfd6139ce7ec4e98dac2b17d8d25934dc99900831e81c3adaef"}, + {file = "bitarray-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:7dfefdcb0dc6a3ba9936063cec65a74595571b375beabe18742b3d91d087eefd"}, + {file = "bitarray-2.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b306c4cf66912511422060f7f5e1149c8bdb404f8e00e600561b0749fdd45659"}, + {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a09c4f81635408e3387348f415521d4b94198c562c23330f560596a6aaa26eaf"}, + {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5361413fd2ecfdf44dc8f065177dc6aba97fa80a91b815586cb388763acf7f8d"}, + {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e8a9475d415ef1eaae7942df6f780fa4dcd48fce32825eda591a17abba869299"}, + {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9b87baa7bfff9a5878fcc1bffe49ecde6e647a72a64b39a69cd8a2992a43a34"}, + {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb6b86cfdfc503e92cb71c68766a24565359136961642504a7cc9faf936d9c88"}, + {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cd56b8ae87ebc71bcacbd73615098e8a8de952ecbb5785b6b4e2b07da8a06e1f"}, + {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3fa909cfd675004aed8b4cc9df352415933656e0155a6209d878b7cb615c787e"}, + {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b069ca9bf728e0c5c5b60e00a89df9af34cc170c695c3bfa3b372d8f40288efb"}, + {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6067f2f07a7121749858c7daa93c8774325c91590b3e81a299621e347740c2ae"}, + {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:321841cdad1dd0f58fe62e80e9c9c7531f8ebf8be93f047401e930dc47425b1e"}, + {file = "bitarray-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:54e16e32e60973bb83c315de9975bc1bcfc9bd50bb13001c31da159bc49b0ca1"}, + {file = "bitarray-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4dcadb7b8034aa3491ee8f5a69b3d9ba9d7d1e55c3cc1fc45be313e708277f8"}, + {file = "bitarray-2.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c8919fdbd3bb596b104388b56ae4b266eb28da1f2f7dff2e1f9334a21840fe96"}, + {file = "bitarray-2.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb7a9d8a2e400a1026de341ad48e21670a6261a75b06df162c5c39b0d0e7c8f4"}, + {file = "bitarray-2.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6ec84668dd7b937874a2b2c293cd14ba84f37be0d196dead852e0ada9815d807"}, + {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2de9a31c34e543ae089fd2a5ced01292f725190e379921384f695e2d7184bd3"}, + {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9521f49ae121a17c0a41e5112249e6fa7f6a571245b1118de81fb86e7c1bc1ce"}, + {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6cc6545d6d76542aee3d18c1c9485fb7b9812b8df4ebe52c4535ec42081b48f"}, + {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:856bbe1616425f71c0df5ef2e8755e878d9504d5a531acba58ab4273c52c117a"}, + {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4bba8042ea6ab331ade91bc435d81ad72fddb098e49108610b0ce7780c14e68"}, + {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a035da89c959d98afc813e3c62f052690d67cfd55a36592f25d734b70de7d4b0"}, + {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6d70b1579da7fb71be5a841a1f965d19aca0ef27f629cfc07d06b09aafd0a333"}, + {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:405b83bed28efaae6d86b6ab287c75712ead0adbfab2a1075a1b7ab47dad4d62"}, + {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7eb8be687c50da0b397d5e0ab7ca200b5ebb639e79a9f5e285851d1944c94be9"}, + {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eceb551dfeaf19c609003a69a0cf8264b0efd7abc3791a11dfabf4788daf0d19"}, + {file = "bitarray-2.9.2-cp38-cp38-win32.whl", hash = "sha256:bb198c6ed1edbcdaf3d1fa3c9c9d1cdb7e179a5134ef5ee660b53cdec43b34e7"}, + {file = "bitarray-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:648d2f2685590b0103c67a937c2fb9e09bcc8dfb166f0c7c77bd341902a6f5b3"}, + {file = "bitarray-2.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ea816dc8f8e65841a8bbdd30e921edffeeb6f76efe6a1eb0da147b60d539d1cf"}, + {file = "bitarray-2.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4d0e32530f941c41eddfc77600ec89b65184cb909c549336463a738fab3ed285"}, + {file = "bitarray-2.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4a22266fb416a3b6c258bf7f83c9fe531ba0b755a56986a81ad69dc0f3bcc070"}, + {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc6d3e80dd8239850f2604833ff3168b28909c8a9357abfed95632cccd17e3e7"}, + {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f135e804986b12bf14f2cd1eb86674c47dea86c4c5f0fa13c88978876b97ebe6"}, + {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87580c7f7d14f7ec401eda7adac1e2a25e95153e9c339872c8ae61b3208819a1"}, + {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64b433e26993127732ac7b66a7821b2537c3044355798de7c5fcb0af34b8296f"}, + {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e497c535f2a9b68c69d36631bf2dba243e05eb343b00b9c7bbdc8c601c6802d"}, + {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e40b3cb9fa1edb4e0175d7c06345c49c7925fe93e39ef55ecb0bc40c906b0c09"}, + {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f2f8692f95c9e377eb19ca519d30d1f884b02feb7e115f798de47570a359e43f"}, + {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f0b84fc50b6dbeced4fa390688c07c10a73222810fb0e08392bd1a1b8259de36"}, + {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d656ad38c942e38a470ddbce26b5020e08e1a7ea86b8fd413bb9024b5189993a"}, + {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6ab0f1dbfe5070db98771a56aa14797595acd45a1af9eadfb193851a270e7996"}, + {file = "bitarray-2.9.2-cp39-cp39-win32.whl", hash = "sha256:0a99b23ac845a9ea3157782c97465e6ae026fe0c7c4c1ed1d88f759fd6ea52d9"}, + {file = "bitarray-2.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:9bbcfc7c279e8d74b076e514e669b683f77b4a2a328585b3f16d4c5259c91222"}, + {file = "bitarray-2.9.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:43847799461d8ba71deb4d97b47250c2c2fb66d82cd3cb8b4caf52bb97c03034"}, + {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f44381b0a4bdf64416082f4f0e7140377ae962c0ced6f983c6d7bbfc034040"}, + {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a484061616fb4b158b80789bd3cb511f399d2116525a8b29b6334c68abc2310f"}, + {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ff9e38356cc803e06134cf8ae9758e836ccd1b793135ef3db53c7c5d71e93bc"}, + {file = "bitarray-2.9.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b44105792fbdcfbda3e26ee88786790fda409da4c71f6c2b73888108cf8f062f"}, + {file = "bitarray-2.9.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7e913098de169c7fc890638ce5e171387363eb812579e637c44261460ac00aa2"}, + {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6fe315355cdfe3ed22ef355b8bdc81a805ca4d0949d921576560e5b227a1112"}, + {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f708e91fdbe443f3bec2df394ed42328fb9b0446dff5cb4199023ac6499e09fd"}, + {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b7b09489b71f9f1f64c0fa0977e250ec24500767dab7383ba9912495849cadf"}, + {file = "bitarray-2.9.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:128cc3488176145b9b137fdcf54c1c201809bbb8dd30b260ee40afe915843b43"}, + {file = "bitarray-2.9.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:21f21e7f56206be346bdbda2a6bdb2165a5e6a11821f88fd4911c5a6bbbdc7e2"}, + {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f4dd3af86dd8a617eb6464622fb64ca86e61ce99b59b5c35d8cd33f9c30603d"}, + {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6465de861aff7a2559f226b37982007417eab8c3557543879987f58b453519bd"}, + {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbaf2bb71d6027152d603f1d5f31e0dfd5e50173d06f877bec484e5396d4594b"}, + {file = "bitarray-2.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2f32948c86e0d230a296686db28191b67ed229756f84728847daa0c7ab7406e3"}, + {file = "bitarray-2.9.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be94e5a685e60f9d24532af8fe5c268002e9016fa80272a94727f435de3d1003"}, + {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5cc9381fd54f3c23ae1039f977bfd6d041a5c3c1518104f616643c3a5a73b15"}, + {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd926e8ae4d1ed1ac4a8f37212a62886292f692bc1739fde98013bf210c2d175"}, + {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:461a3dafb9d5fda0bb3385dc507d78b1984b49da3fe4c6d56c869a54373b7008"}, + {file = "bitarray-2.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:393cb27fd859af5fd9c16eb26b1c59b17b390ff66b3ae5d0dd258270191baf13"}, + {file = "bitarray-2.9.2.tar.gz", hash = "sha256:a8f286a51a32323715d77755ed959f94bef13972e9a2fe71b609e40e6d27957e"}, ] [[package]] @@ -289,62 +269,64 @@ files = [ [[package]] name = "cbor2" -version = "5.4.6" +version = "5.6.0" description = "CBOR (de)serializer with extensive tag support" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "cbor2-5.4.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:309fffbb7f561d67f02095d4b9657b73c9220558701c997e9bfcfbca2696e927"}, - {file = "cbor2-5.4.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ff95b33e5482313a74648ca3620c9328e9f30ecfa034df040b828e476597d352"}, - {file = "cbor2-5.4.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db9eb582fce972f0fa429d8159b7891ff8deccb7affc4995090afc61ce0d328a"}, - {file = "cbor2-5.4.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3950be57a1698086cf26d8710b4e5a637b65133c5b1f9eec23967d4089d8cfed"}, - {file = "cbor2-5.4.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:78304df140b9e13b93bcbb2aecee64c9aaa9f1cadbd45f043b5e7b93cc2f21a2"}, - {file = "cbor2-5.4.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e73ca40dd3c7210ff776acff9869ddc9ff67bae7c425b58e5715dcf55275163f"}, - {file = "cbor2-5.4.6-cp310-cp310-win_amd64.whl", hash = "sha256:0b956f19e93ba3180c336282cd1b6665631f2d3a196a9c19b29a833bf979e7a4"}, - {file = "cbor2-5.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c12c0ab78f5bc290b08a79152a8621822415836a86f8f4b50dadba371736fda"}, - {file = "cbor2-5.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3545b16f9f0d5f34d4c99052829c3726020a07be34c99c250d0df87418f02954"}, - {file = "cbor2-5.4.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24144822f8d2b0156f4cda9427f071f969c18683ffed39663dc86bc0a75ae4dd"}, - {file = "cbor2-5.4.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1835536e76ea16e88c934aac5e369ba9f93d495b01e5fa2d93f0b4986b89146d"}, - {file = "cbor2-5.4.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:39452c799453f5bf33281ffc0752c620b8bfa0b7c13070b87d370257a1311976"}, - {file = "cbor2-5.4.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3316f09a77af85e7772ecfdd693b0f450678a60b1aee641bac319289757e3fa0"}, - {file = "cbor2-5.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:456cdff668a50a52fdb8aa6d0742511e43ed46d6a5b463dba80a5a720fa0d320"}, - {file = "cbor2-5.4.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9394ca49ecdf0957924e45d09a4026482d184a465a047f60c4044eb464c43de9"}, - {file = "cbor2-5.4.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56dfa030cd3d67e5b6701d3067923f2f61536a8ffb1b45be14775d1e866b59ae"}, - {file = "cbor2-5.4.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5094562dfe3e5583202b93ef7ca5082c2ba5571accb2c4412d27b7d0ba8a563"}, - {file = "cbor2-5.4.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:94f844d0e232aca061a86dd6ff191e47ba0389ddd34acb784ad9a41594dc99a4"}, - {file = "cbor2-5.4.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7bbd3470eb685325398023e335be896b74f61b014896604ed45049a7b7b6d8ac"}, - {file = "cbor2-5.4.6-cp37-cp37m-win_amd64.whl", hash = "sha256:0bd12c54a48949d11f5ffc2fa27f5df1b4754111f5207453e5fae3512ebb3cab"}, - {file = "cbor2-5.4.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2984a488f350aee1d54fa9cb8c6a3c1f1f5b268abbc91161e47185de4d829f3"}, - {file = "cbor2-5.4.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c285a2cb2c04004bfead93df89d92a0cef1874ad337d0cb5ea53c2c31e97bfdb"}, - {file = "cbor2-5.4.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6709d97695205cd08255363b54afa035306d5302b7b5e38308c8ff5a47e60f2a"}, - {file = "cbor2-5.4.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96087fa5336ebfc94465c0768cd5de0fcf9af3840d2cf0ce32f5767855f1a293"}, - {file = "cbor2-5.4.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0d2b926b024d3a1549b819bc82fdc387062bbd977b0299dd5fa5e0ea3267b98b"}, - {file = "cbor2-5.4.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6e1b5aee920b6a2f737aa12e2b54de3826b09f885a7ce402db84216343368140"}, - {file = "cbor2-5.4.6-cp38-cp38-win_amd64.whl", hash = "sha256:79e048e623846d60d735bb350263e8fdd36cb6195d7f1a2b57eacd573d9c0b33"}, - {file = "cbor2-5.4.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80ac8ba450c7a41c5afe5f7e503d3092442ed75393e1de162b0bf0d97edf7c7f"}, - {file = "cbor2-5.4.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ce1a2c272ba8523a55ea2f1d66e3464e89fa0e37c9a3d786a919fe64e68dbd7"}, - {file = "cbor2-5.4.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1618d16e310f7ffed141762b0ff5d8bb6b53ad449406115cc465bf04213cefcf"}, - {file = "cbor2-5.4.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bbbdb2e3ef274865dc3f279aae109b5d94f4654aea3c72c479fb37e4a1e7ed7"}, - {file = "cbor2-5.4.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6f9c702bee2954fffdfa3de95a5af1a6b1c5f155e39490353d5654d83bb05bb9"}, - {file = "cbor2-5.4.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b9f3924da0e460a93b3674c7e71020dd6c9e9f17400a34e52a88c0af2dcd2aa"}, - {file = "cbor2-5.4.6-cp39-cp39-win_amd64.whl", hash = "sha256:d54bd840b4fe34f097b8665fc0692c7dd175349e53976be6c5de4433b970daa4"}, - {file = "cbor2-5.4.6-py3-none-any.whl", hash = "sha256:181ac494091d1f9c5bb373cd85514ce1eb967a8cf3ec298e8dfa8878aa823956"}, - {file = "cbor2-5.4.6.tar.gz", hash = "sha256:b893500db0fe033e570c3adc956af6eefc57e280026bd2d86fd53da9f1e594d7"}, -] - -[package.extras] -doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["pytest", "pytest-cov"] + {file = "cbor2-5.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7569627514699b10d903795e344e5520cd758f7db968e46e667b6875c409610b"}, + {file = "cbor2-5.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e6d5c5b5cb25450561c92c9ac7d72912027cfa8807aab77ea6f5549e2157335"}, + {file = "cbor2-5.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19403d65c32709c4940ae729470dd77ed88ebbd4972355d0ec23ff4dbe34faa3"}, + {file = "cbor2-5.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329196be76fbba0ad63926913eb225dddcfc4891ff6760484fdcf071cebc7188"}, + {file = "cbor2-5.6.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ac835523af0e37086b5f6aac9283e45cffdf6fa0f1be5eecf967014e7184d948"}, + {file = "cbor2-5.6.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:63ab6734098c494687b26531ed4d44c06f287a44061ae1bc16b3fa65563d80b0"}, + {file = "cbor2-5.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:777897d46e31bc2683ed9e015a9c97fc97929bf78d620fc3361fe39a86912eba"}, + {file = "cbor2-5.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5d3932c3f0637439f121a54b9e6020e62e9f2620751b2e850a6f09f1c1ee299e"}, + {file = "cbor2-5.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f017d451b9b7e45759e9ffbfae8a2b1bda3f6a547d6451f7761655a8438f956"}, + {file = "cbor2-5.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c66cf65766195c310b2134ceeb20927fce85373d13483e97d2211dd499739f9b"}, + {file = "cbor2-5.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2411ad0fc8817ff38076523bfc43d193188eedcb0d3a1c52428672636f3760d4"}, + {file = "cbor2-5.6.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b5ce2c7c9172c401db047202029f96a5799c68ff0c936874c596e3718cd383e4"}, + {file = "cbor2-5.6.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1a4e1bb41ac5dc27bd4737c92934e9daf38440ce849eaf3e25da24f9d1fd2195"}, + {file = "cbor2-5.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:83736e076e878f3679ef2dd6cfce5ebcb71f65f9eeada1d14b16b5b87dbc2250"}, + {file = "cbor2-5.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8724f172b581414444801bd7e4974a1512822231e30162c7d5a6374a3c89ddbf"}, + {file = "cbor2-5.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ae83ca762a60b43c83c23edf487e41dc90ba7cc98e25134cde2bf09e99ec1fa3"}, + {file = "cbor2-5.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0da8f4aed346ff0ce667254331d341ad27d8d62c8813536f019d8a68aef40eba"}, + {file = "cbor2-5.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99780a5fe8e23a467eb1084feb74b9bdc6598f0eb6c09821b00bb65ddd834d67"}, + {file = "cbor2-5.6.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f0167b4fd537db4925ee8c2890fb950493280628d9c18034625fa5c8a96db689"}, + {file = "cbor2-5.6.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8a073761d9148e4ffbfb0e4125643c059a4d5d5c5c5448cd56759765e1113487"}, + {file = "cbor2-5.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:62ced11efb37729e1a2a5f04fb8c2661d46ae6adbdddc23cb31ffad2ec75ff7a"}, + {file = "cbor2-5.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0130d50aa1cd0ba8ce65eda5bbbb57bda3f2c9cd86bba7d8be5e3c9b19f88f93"}, + {file = "cbor2-5.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:29ba57a33fcffd5d70fd6ac1182520e887918f9d2b6225a06eaae029f070e18f"}, + {file = "cbor2-5.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe7a459aae6ca4abdc490fdf89463cbeea3449569eca853af7c2672286edcea0"}, + {file = "cbor2-5.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0c098a2802ec1df0a6e96c415203c8a52c42158e1e07d8074c9acf19bcc146f"}, + {file = "cbor2-5.6.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3184d91a855aedb6f0e76e5ac548a1e43a7fcd3d5ba2deb0894b81c77c2c461"}, + {file = "cbor2-5.6.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:622b4fe945ecdd93df8c21169c8f1a85dcf21d78ecb1e8b7f9f2795520480010"}, + {file = "cbor2-5.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:aaf6a424742f55e2991c7013df02a629d24c64e5730c3fd3aebcbbebc580bfab"}, + {file = "cbor2-5.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e1ff25fb1b6bafbdb192037860471962f59ce9c1f584611572360e15725abbb1"}, + {file = "cbor2-5.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4143152579ff9e0668688d6d41e2f6a20161f8dc5af97b1b92f400d3112888af"}, + {file = "cbor2-5.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df7b7cf96e9027138129edbfa0e2024d6f4beb7db42c2a992ab867eff3c04d46"}, + {file = "cbor2-5.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:789496ece76712c298f1fd4681d074f6828ed0d788076c5949c4474c11291f68"}, + {file = "cbor2-5.6.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3d8525d4f525add7971b75b7ff947eed085405d9db7ad6fad456909cbffd18c1"}, + {file = "cbor2-5.6.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c9423aaf110ce7c3e856f2d5dc6ece7358de48bad7a88d2633f5943d5cd20676"}, + {file = "cbor2-5.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:52fa913133b82578244e6b86b8dff9d88c9d13acf84955b6942650689f302c01"}, + {file = "cbor2-5.6.0-py3-none-any.whl", hash = "sha256:7ba2d0abbb199dd08b7ea59038dbf6524277f124d836b66744cfdd49d31fd012"}, + {file = "cbor2-5.6.0.tar.gz", hash = "sha256:9d94e2226f8f5792fdba5ab20e07b9bfe02e76c10c3ca126418cd4310439d002"}, +] + +[package.extras] +benchmarks = ["pytest-benchmark (==4.0.0)"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)", "typing-extensions"] +test = ["coverage (>=7)", "hypothesis", "pytest"] [[package]] name = "certifi" -version = "2023.7.22" +version = "2023.11.17" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, ] [[package]] @@ -424,117 +406,117 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.0" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.0.tar.gz", hash = "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-win32.whl", hash = "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-win32.whl", hash = "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-win32.whl", hash = "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-win32.whl", hash = "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-win32.whl", hash = "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-win32.whl", hash = "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884"}, - {file = "charset_normalizer-3.3.0-py3-none-any.whl", hash = "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] name = "cleo" -version = "2.0.1" +version = "2.1.0" description = "Cleo allows you to create beautiful and testable command-line interfaces." optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "cleo-2.0.1-py3-none-any.whl", hash = "sha256:6eb133670a3ed1f3b052d53789017b6e50fca66d1287e6e6696285f4cb8ea448"}, - {file = "cleo-2.0.1.tar.gz", hash = "sha256:eb4b2e1f3063c11085cebe489a6e9124163c226575a3c3be69b2e51af4a15ec5"}, + {file = "cleo-2.1.0-py3-none-any.whl", hash = "sha256:4a31bd4dd45695a64ee3c4758f583f134267c2bc518d8ae9a29cf237d009b07e"}, + {file = "cleo-2.1.0.tar.gz", hash = "sha256:0b2c880b5d13660a7ea651001fb4acb527696c01f15c9ee650f377aa543fd523"}, ] [package.dependencies] crashtest = ">=0.4.1,<0.5.0" -rapidfuzz = ">=2.2.0,<3.0.0" +rapidfuzz = ">=3.0.0,<4.0.0" [[package]] name = "click" @@ -561,20 +543,6 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "commonmark" -version = "0.9.1" -description = "Python parser for the CommonMark Markdown spec" -optional = false -python-versions = "*" -files = [ - {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, - {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, -] - -[package.extras] -test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] - [[package]] name = "crashtest" version = "0.4.1" @@ -588,149 +556,169 @@ files = [ [[package]] name = "cryptography" -version = "41.0.4" +version = "42.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839"}, - {file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143"}, - {file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397"}, - {file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860"}, - {file = "cryptography-41.0.4-cp37-abi3-win32.whl", hash = "sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd"}, - {file = "cryptography-41.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311"}, - {file = "cryptography-41.0.4.tar.gz", hash = "sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a"}, + {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be"}, + {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529"}, + {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9"}, + {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2"}, + {file = "cryptography-42.0.2-cp37-abi3-win32.whl", hash = "sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee"}, + {file = "cryptography-42.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee"}, + {file = "cryptography-42.0.2-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90"}, + {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea"}, + {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33"}, + {file = "cryptography-42.0.2-cp39-abi3-win32.whl", hash = "sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635"}, + {file = "cryptography-42.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2"}, + {file = "cryptography-42.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a"}, + {file = "cryptography-42.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65"}, + {file = "cryptography-42.0.2.tar.gz", hash = "sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888"}, ] [package.dependencies] -cffi = ">=1.12" +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] nox = ["nox"] -pep8test = ["black", "check-sdist", "mypy", "ruff"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] name = "cytoolz" -version = "0.12.2" +version = "0.12.3" description = "Cython implementation of Toolz: High performance functional utilities" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "cytoolz-0.12.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bff49986c9bae127928a2f9fd6313146a342bfae8292f63e562f872bd01b871"}, - {file = "cytoolz-0.12.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:908c13f305d34322e11b796de358edaeea47dd2d115c33ca22909c5e8fb036fd"}, - {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:735147aa41b8eeb104da186864b55e2a6623c758000081d19c93d759cd9523e3"}, - {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7d352d4de060604e605abdc5c8a5d0429d5f156cb9866609065d3003454d4cea"}, - {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89247ac220031a4f9f689688bcee42b38fd770d4cce294e5d914afc53b630abe"}, - {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9070ae35c410d644e6df98a8f69f3ed2807e657d0df2a26b2643127cbf6944a5"}, - {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:843500cd3e4884b92fd4037912bc42d5f047108d2c986d36352e880196d465b0"}, - {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6a93644d7996fd696ab7f1f466cd75d718d0a00d5c8118b9fe8c64231dc1f85e"}, - {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:96796594c770bc6587376e74ddc7d9c982d68f47116bb69d90873db5e0ea88b6"}, - {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:48425107fbb1af3f0f2410c004f16be10ffc9374358e5600b57fa543f46f8def"}, - {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:cde6dbb788a4cbc4a80a72aa96386ba4c2b17bdfff3ace0709799adbe16d6476"}, - {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68ae7091cc73a752f0b938f15bb193de80ca5edf5ae2ea6360d93d3e9228357b"}, - {file = "cytoolz-0.12.2-cp310-cp310-win32.whl", hash = "sha256:997b7e0960072f6bb445402da162f964ea67387b9f18bda2361edcc026e13597"}, - {file = "cytoolz-0.12.2-cp310-cp310-win_amd64.whl", hash = "sha256:663911786dcde3e4a5d88215c722c531c7548903dc07d418418c0d1c768072c0"}, - {file = "cytoolz-0.12.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a7d8b869ded171f6cdf584fc2fc6ae03b30a0e1e37a9daf213a59857a62ed90"}, - {file = "cytoolz-0.12.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9b28787eaf2174e68f0acb3c66f9c6b98bdfeb0930c0d0b08e1941c7aedc8d27"}, - {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00547da587f124b32b072ce52dd5e4b37cf199fedcea902e33c67548523e4678"}, - {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:275d53fd769df2102d6c9fc98e553bd8a9a38926f54d6b20cf29f0dd00bf3b75"}, - {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5556acde785a61d4cf8b8534ae109b023cbd2f9df65ee2afbe070be47c410f8c"}, - {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b41a85b9b9a2530b72b0d3d10e383fc3c2647ae88169d557d5e216f881860318"}, - {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673d6e9e3aa86949343b46ac2b7be266c36e07ce77fa1d40f349e6987a814d6e"}, - {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81e6a9a8fda78a2f4901d2915b25bf620f372997ca1f20a14f7cefef5ad6f6f4"}, - {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fa44215bc31675a6380cd896dadb7f2054a7b94cfb87e53e52af844c65406a54"}, - {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a08b4346350660799d81d4016e748bcb134a9083301d41f9618f64a6077f89f2"}, - {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2fb740482794a72e2e5fec58e4d9b00dcd5a60a8cef68431ff12f2ba0e0d9a7e"}, - {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9007bb1290c79402be6b84bcf9e7a622a073859d61fcee146dc7bc47afe328f3"}, - {file = "cytoolz-0.12.2-cp311-cp311-win32.whl", hash = "sha256:a973f5286758f76824ecf19ae1999f6697371a9121c8f163295d181d19a819d7"}, - {file = "cytoolz-0.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:1ce324d1b413636ea5ee929f79637821f13c9e55e9588f38228947294944d2ed"}, - {file = "cytoolz-0.12.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c08094b9e5d1b6dfb0845a0253cc2655ca64ce70d15162dfdb102e28c8993493"}, - {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baf020f4b708f800b353259cd7575e335a79f1ac912d9dda55b2aa0bf3616e42"}, - {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4416ee86a87180b6a28e7483102c92debc077bec59c67eda8cc63fc52a218ac0"}, - {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6ee222671eed5c5b16a5ad2aea07f0a715b8b199ee534834bc1dd2798f1ade7"}, - {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad92e37be0b106fdbc575a3a669b43b364a5ef334495c9764de4c2d7541f7a99"}, - {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:460c05238fbfe6d848141669d17a751a46c923f9f0c9fd8a3a462ab737623a44"}, - {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9e5075e30be626ef0f9bedf7a15f55ed4d7209e832bc314fdc232dbd61dcbf44"}, - {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:03b58f843f09e73414e82e57f7e8d88f087eaabf8f276b866a40661161da6c51"}, - {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:5e4e612b7ecc9596e7c859cd9e0cd085e6d0c576b4f0d917299595eb56bf9c05"}, - {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:08a0e03f287e45eb694998bb55ac1643372199c659affa8319dfbbdec7f7fb3c"}, - {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b029bdd5a8b6c9a7c0e8fdbe4fc25ffaa2e09b77f6f3462314696e3a20511829"}, - {file = "cytoolz-0.12.2-cp36-cp36m-win32.whl", hash = "sha256:18580d060fa637ff01541640ecde6de832a248df02b8fb57e6dd578f189d62c7"}, - {file = "cytoolz-0.12.2-cp36-cp36m-win_amd64.whl", hash = "sha256:97cf514a9f3426228d8daf880f56488330e4b2948a6d183a106921217850d9eb"}, - {file = "cytoolz-0.12.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18a0f838677f9510aef0330c0096778dd6406d21d4ff9504bf79d85235a18460"}, - {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb081b2b02bf4405c804de1ece6f904916838ab0e057f1446e4ac12fac827960"}, - {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57233e1600560ceb719bed759dc78393edd541b9a3e7fefc3079abd83c26a6ea"}, - {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0295289c4510efa41174850e75bc9188f82b72b1b54d0ea57d1781729c2924d5"}, - {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a92aab8dd1d427ac9bc7480cfd3481dbab0ef024558f2f5a47de672d8a5ffaa"}, - {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51d3495235af09f21aa92a7cdd51504bda640b108b6be834448b774f52852c09"}, - {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9c690b359f503f18bf1c46a6456370e4f6f3fc4320b8774ae69c4f85ecc6c94"}, - {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:481e3129a76ea01adcc0e7097ccb8dbddab1cfc40b6f0e32c670153512957c0f"}, - {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:55e94124af9c8fbb1df54195cc092688fdad0765641b738970b6f1d5ea72e776"}, - {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5616d386dfbfba7c39e9418ba668c734f6ceaacc0130877e8a100cad11e6838b"}, - {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:732d08228fa8d366fec284f7032cc868d28a99fa81fc71e3adf7ecedbcf33a0f"}, - {file = "cytoolz-0.12.2-cp37-cp37m-win32.whl", hash = "sha256:f039c5373f7b314b151432c73219216857b19ab9cb834f0eb5d880f74fc7851c"}, - {file = "cytoolz-0.12.2-cp37-cp37m-win_amd64.whl", hash = "sha256:246368e983eaee9851b15d7755f82030eab4aa82098d2a34f6bef9c689d33fcc"}, - {file = "cytoolz-0.12.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:81074edf3c74bc9bd250d223408a5df0ff745d1f7a462597536cd26b9390e2d6"}, - {file = "cytoolz-0.12.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:960d85ebaa974ecea4e71fa56d098378fa51fd670ee744614cbb95bf95e28fc7"}, - {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c8d0dff4865da54ae825d43e1721925721b19f3b9aca8e730c2ce73dee2c630"}, - {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a9d12436fd64937bd2c9609605f527af7f1a8db6e6637639b44121c0fe715d6"}, - {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd461e402e24929d866f05061d2f8337e3a8456e75e21b72c125abff2477c7f7"}, - {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0568d4da0a9ee9f9f5ab318f6501557f1cfe26d18c96c8e0dac7332ae04c6717"}, - {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:101b5bd32badfc8b1f9c7be04ba3ae04fb47f9c8736590666ce9449bff76e0b1"}, - {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8bb624dbaef4661f5e3625c1e39ad98ecceef281d1380e2774d8084ad0810275"}, - {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3e993804e6b04113d61fdb9541b6df2f096ec265a506dad7437517470919c90f"}, - {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ab911033e5937fc221a2c165acce7f66ae5ac9d3e54bec56f3c9c197a96be574"}, - {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6de6a4bdfaee382c2de2a3580b3ae76fce6105da202bbd835e5efbeae6a9c6e"}, - {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9480b4b327be83c4d29cb88bcace761b11f5e30198ffe2287889455c6819e934"}, - {file = "cytoolz-0.12.2-cp38-cp38-win32.whl", hash = "sha256:4180b2785d1278e6abb36a72ac97c92432db53fa2df00ee943d2c15a33627d31"}, - {file = "cytoolz-0.12.2-cp38-cp38-win_amd64.whl", hash = "sha256:d0086ba8d41d73647b13087a3ca9c020f6bfec338335037e8f5172b4c7c8dce5"}, - {file = "cytoolz-0.12.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d29988bde28a90a00367edcf92afa1a2f7ecf43ea3ae383291b7da6d380ccc25"}, - {file = "cytoolz-0.12.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:24c0d71e9ac91f4466b1bd280f7de43aa4d94682daaf34d85d867a9b479b87cc"}, - {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa436abd4ac9ca71859baf5794614e6ec8fa27362f0162baedcc059048da55f7"}, - {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45c7b4eac7571707269ebc2893facdf87e359cd5c7cfbfa9e6bd8b33fb1079c5"}, - {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:294d24edc747ef4e1b28e54365f713becb844e7898113fafbe3e9165dc44aeea"}, - {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:478051e5ef8278b2429864c8d148efcebdc2be948a61c9a44757cd8c816c98f5"}, - {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14108cafb140dd68fdda610c2bbc6a37bf052cd48cfebf487ed44145f7a2b67f"}, - {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fef7b602ccf8a3c77ab483479ccd7a952a8c5bb1c263156671ba7aaa24d1035"}, - {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9bf51354e15520715f068853e6ab8190e77139940e8b8b633bdb587956a08fb0"}, - {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:388f840fd911d61a96e9e595eaf003f9dc39e847c9060b8e623ab29e556f009b"}, - {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a67f75cc51a2dc7229a8ac84291e4d61dc5abfc8940befcf37a2836d95873340"}, - {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63b31345e20afda2ae30dba246955517a4264464d75e071fc2fa641e88c763ec"}, - {file = "cytoolz-0.12.2-cp39-cp39-win32.whl", hash = "sha256:f6e86ac2b45a95f75c6f744147483e0fc9697ce7dfe1726083324c236f873f8b"}, - {file = "cytoolz-0.12.2-cp39-cp39-win_amd64.whl", hash = "sha256:5998f81bf6a2b28a802521efe14d9fc119f74b64e87b62ad1b0e7c3d8366d0c7"}, - {file = "cytoolz-0.12.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:593e89e2518eaf81e96edcc9ef2c5fca666e8fc922b03d5cb7a7b8964dbee336"}, - {file = "cytoolz-0.12.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff451d614ca1d4227db0ffa627fb51df71968cf0d9baf0210528dad10fdbc3ab"}, - {file = "cytoolz-0.12.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad9ea4a50d2948738351790047d45f2b1a023facc01bf0361988109b177e8b2f"}, - {file = "cytoolz-0.12.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbe038bb78d599b5a29d09c438905defaa615a522bc7e12f8016823179439497"}, - {file = "cytoolz-0.12.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d494befe648c13c98c0f3d56d05489c839c9228a32f58e9777305deb6c2c1cee"}, - {file = "cytoolz-0.12.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c26805b6c8dc8565ed91045c44040bf6c0fe5cb5b390c78cd1d9400d08a6cd39"}, - {file = "cytoolz-0.12.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4e32badb2ccf1773e1e74020b7e3b8caf9e92f842c6be7d14888ecdefc2c6c"}, - {file = "cytoolz-0.12.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce7889dc3701826d519ede93cdff11940fb5567dbdc165dce0e78047eece02b7"}, - {file = "cytoolz-0.12.2-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c820608e7077416f766b148d75e158e454881961881b657cff808529d261dd24"}, - {file = "cytoolz-0.12.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:698da4fa1f7baeea0607738cb1f9877ed1ba50342b29891b0223221679d6f729"}, - {file = "cytoolz-0.12.2.tar.gz", hash = "sha256:31d4b0455d72d914645f803d917daf4f314d115c70de0578d3820deb8b101f66"}, + {file = "cytoolz-0.12.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bbe58e26c84b163beba0fbeacf6b065feabc8f75c6d3fe305550d33f24a2d346"}, + {file = "cytoolz-0.12.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c51b66ada9bfdb88cf711bf350fcc46f82b83a4683cf2413e633c31a64df6201"}, + {file = "cytoolz-0.12.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e70d9c615e5c9dc10d279d1e32e846085fe1fd6f08d623ddd059a92861f4e3dd"}, + {file = "cytoolz-0.12.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a83f4532707963ae1a5108e51fdfe1278cc8724e3301fee48b9e73e1316de64f"}, + {file = "cytoolz-0.12.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d028044524ee2e815f36210a793c414551b689d4f4eda28f8bbb0883ad78bf5f"}, + {file = "cytoolz-0.12.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c2875bcd1397d0627a09a4f9172fa513185ad302c63758efc15b8eb33cc2a98"}, + {file = "cytoolz-0.12.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:131ff4820e5d64a25d7ad3c3556f2d8aa65c66b3f021b03f8a8e98e4180dd808"}, + {file = "cytoolz-0.12.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:04afa90d9d9d18394c40d9bed48c51433d08b57c042e0e50c8c0f9799735dcbd"}, + {file = "cytoolz-0.12.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:dc1ca9c610425f9854323669a671fc163300b873731584e258975adf50931164"}, + {file = "cytoolz-0.12.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bfa3f8e01bc423a933f2e1c510cbb0632c6787865b5242857cc955cae220d1bf"}, + {file = "cytoolz-0.12.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:f702e295dddef5f8af4a456db93f114539b8dc2a7a9bc4de7c7e41d169aa6ec3"}, + {file = "cytoolz-0.12.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0fbad1fb9bb47e827d00e01992a099b0ba79facf5e5aa453be066033232ac4b5"}, + {file = "cytoolz-0.12.3-cp310-cp310-win32.whl", hash = "sha256:8587c3c3dbe78af90c5025288766ac10dc2240c1e76eb0a93a4e244c265ccefd"}, + {file = "cytoolz-0.12.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e45803d9e75ef90a2f859ef8f7f77614730f4a8ce1b9244375734567299d239"}, + {file = "cytoolz-0.12.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3ac4f2fb38bbc67ff1875b7d2f0f162a247f43bd28eb7c9d15e6175a982e558d"}, + {file = "cytoolz-0.12.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0cf1e1e96dd86829a0539baf514a9c8473a58fbb415f92401a68e8e52a34ecd5"}, + {file = "cytoolz-0.12.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08a438701c6141dd34eaf92e9e9a1f66e23a22f7840ef8a371eba274477de85d"}, + {file = "cytoolz-0.12.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6b6f11b0d7ed91be53166aeef2a23a799e636625675bb30818f47f41ad31821"}, + {file = "cytoolz-0.12.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7fde09384d23048a7b4ac889063761e44b89a0b64015393e2d1d21d5c1f534a"}, + {file = "cytoolz-0.12.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d3bfe45173cc8e6c76206be3a916d8bfd2214fb2965563e288088012f1dabfc"}, + {file = "cytoolz-0.12.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27513a5d5b6624372d63313574381d3217a66e7a2626b056c695179623a5cb1a"}, + {file = "cytoolz-0.12.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d294e5e81ff094fe920fd545052ff30838ea49f9e91227a55ecd9f3ca19774a0"}, + {file = "cytoolz-0.12.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:727b01a2004ddb513496507a695e19b5c0cfebcdfcc68349d3efd92a1c297bf4"}, + {file = "cytoolz-0.12.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:fe1e1779a39dbe83f13886d2b4b02f8c4b10755e3c8d9a89b630395f49f4f406"}, + {file = "cytoolz-0.12.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:de74ef266e2679c3bf8b5fc20cee4fc0271ba13ae0d9097b1491c7a9bcadb389"}, + {file = "cytoolz-0.12.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e04d22049233394e0b08193aca9737200b4a2afa28659d957327aa780ddddf2"}, + {file = "cytoolz-0.12.3-cp311-cp311-win32.whl", hash = "sha256:20d36430d8ac809186736fda735ee7d595b6242bdb35f69b598ef809ebfa5605"}, + {file = "cytoolz-0.12.3-cp311-cp311-win_amd64.whl", hash = "sha256:780c06110f383344d537f48d9010d79fa4f75070d214fc47f389357dd4f010b6"}, + {file = "cytoolz-0.12.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:86923d823bd19ce35805953b018d436f6b862edd6a7c8b747a13d52b39ed5716"}, + {file = "cytoolz-0.12.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3e61acfd029bfb81c2c596249b508dfd2b4f72e31b7b53b62e5fb0507dd7293"}, + {file = "cytoolz-0.12.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd728f4e6051af6af234651df49319da1d813f47894d4c3c8ab7455e01703a37"}, + {file = "cytoolz-0.12.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe8c6267caa7ec67bcc37e360f0d8a26bc3bdce510b15b97f2f2e0143bdd3673"}, + {file = "cytoolz-0.12.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99462abd8323c52204a2a0ce62454ce8fa0f4e94b9af397945c12830de73f27e"}, + {file = "cytoolz-0.12.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da125221b1fa25c690fcd030a54344cecec80074df018d906fc6a99f46c1e3a6"}, + {file = "cytoolz-0.12.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c18e351956f70db9e2d04ff02f28e9a41839250d3f936a4c8a1eabd1c3094d2"}, + {file = "cytoolz-0.12.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:921e6d2440ac758c4945c587b1d1d9b781b72737ac0c0ca5d5e02ca1db8bded2"}, + {file = "cytoolz-0.12.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1651a9bd591a8326329ce1d6336f3129161a36d7061a4d5ea9e5377e033364cf"}, + {file = "cytoolz-0.12.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8893223b87c2782bd59f9c4bd5c7bf733edd8728b523c93efb91d7468b486528"}, + {file = "cytoolz-0.12.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:e4d2961644153c5ae186db964aa9f6109da81b12df0f1d3494b4e5cf2c332ee2"}, + {file = "cytoolz-0.12.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:71b6eb97f6695f7ba8ce69c49b707a351c5f46fd97f5aeb5f6f2fb0d6e72b887"}, + {file = "cytoolz-0.12.3-cp312-cp312-win32.whl", hash = "sha256:cee3de65584e915053412cd178729ff510ad5f8f585c21c5890e91028283518f"}, + {file = "cytoolz-0.12.3-cp312-cp312-win_amd64.whl", hash = "sha256:9eef0d23035fa4dcfa21e570961e86c375153a7ee605cdd11a8b088c24f707f6"}, + {file = "cytoolz-0.12.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9a38332cfad2a91e89405b7c18b3f00e2edc951c225accbc217597d3e4e9fde"}, + {file = "cytoolz-0.12.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f501ae1353071fa5d6677437bbeb1aeb5622067dce0977cedc2c5ec5843b202"}, + {file = "cytoolz-0.12.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56f899758146a52e2f8cfb3fb6f4ca19c1e5814178c3d584de35f9e4d7166d91"}, + {file = "cytoolz-0.12.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:800f0526adf9e53d3c6acda748f4def1f048adaa780752f154da5cf22aa488a2"}, + {file = "cytoolz-0.12.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0976a3fcb81d065473173e9005848218ce03ddb2ec7d40dd6a8d2dba7f1c3ae"}, + {file = "cytoolz-0.12.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c835eab01466cb67d0ce6290601ebef2d82d8d0d0a285ed0d6e46989e4a7a71a"}, + {file = "cytoolz-0.12.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4fba0616fcd487e34b8beec1ad9911d192c62e758baa12fcb44448b9b6feae22"}, + {file = "cytoolz-0.12.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6f6e8207d732651e0204779e1ba5a4925c93081834570411f959b80681f8d333"}, + {file = "cytoolz-0.12.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:8119bf5961091cfe644784d0bae214e273b3b3a479f93ee3baab97bbd995ccfe"}, + {file = "cytoolz-0.12.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:7ad1331cb68afeec58469c31d944a2100cee14eac221553f0d5218ace1a0b25d"}, + {file = "cytoolz-0.12.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:92c53d508fb8a4463acc85b322fa24734efdc66933a5c8661bdc862103a3373d"}, + {file = "cytoolz-0.12.3-cp37-cp37m-win32.whl", hash = "sha256:2c6dd75dae3d84fa8988861ab8b1189d2488cb8a9b8653828f9cd6126b5e7abd"}, + {file = "cytoolz-0.12.3-cp37-cp37m-win_amd64.whl", hash = "sha256:caf07a97b5220e6334dd32c8b6d8b2bd255ca694eca5dfe914bb5b880ee66cdb"}, + {file = "cytoolz-0.12.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ed0cfb9326747759e2ad81cb6e45f20086a273b67ac3a4c00b19efcbab007c60"}, + {file = "cytoolz-0.12.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:96a5a0292575c3697121f97cc605baf2fd125120c7dcdf39edd1a135798482ca"}, + {file = "cytoolz-0.12.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b76f2f50a789c44d6fd7f773ec43d2a8686781cd52236da03f7f7d7998989bee"}, + {file = "cytoolz-0.12.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2905fdccacc64b4beba37f95cab9d792289c80f4d70830b70de2fc66c007ec01"}, + {file = "cytoolz-0.12.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ebe23028eac51251f22ba01dba6587d30aa9c320372ca0c14eeab67118ec3f"}, + {file = "cytoolz-0.12.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96c715404a3825e37fe3966fe84c5f8a1f036e7640b2a02dbed96cac0c933451"}, + {file = "cytoolz-0.12.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bac0adffc1b6b6a4c5f1fd1dd2161afb720bcc771a91016dc6bdba59af0a5d3"}, + {file = "cytoolz-0.12.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:37441bf4a2a4e2e0fe9c3b0ea5e72db352f5cca03903977ffc42f6f6c5467be9"}, + {file = "cytoolz-0.12.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f04037302049cb30033f7fa4e1d0e44afe35ed6bfcf9b380fc11f2a27d3ed697"}, + {file = "cytoolz-0.12.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f37b60e66378e7a116931d7220f5352186abfcc950d64856038aa2c01944929c"}, + {file = "cytoolz-0.12.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ec9be3e4b6f86ea8b294d34c990c99d2ba6c526ef1e8f46f1d52c263d4f32cd7"}, + {file = "cytoolz-0.12.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0e9199c9e3fbf380a92b8042c677eb9e7ed4bccb126de5e9c0d26f5888d96788"}, + {file = "cytoolz-0.12.3-cp38-cp38-win32.whl", hash = "sha256:18cd61e078bd6bffe088e40f1ed02001387c29174750abce79499d26fa57f5eb"}, + {file = "cytoolz-0.12.3-cp38-cp38-win_amd64.whl", hash = "sha256:765b8381d4003ceb1a07896a854eee2c31ebc950a4ae17d1e7a17c2a8feb2a68"}, + {file = "cytoolz-0.12.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b4a52dd2a36b0a91f7aa50ca6c8509057acc481a24255f6cb07b15d339a34e0f"}, + {file = "cytoolz-0.12.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:581f1ce479769fe7eeb9ae6d87eadb230df8c7c5fff32138162cdd99d7fb8fc3"}, + {file = "cytoolz-0.12.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46f505d4c6eb79585c8ad0b9dc140ef30a138c880e4e3b40230d642690e36366"}, + {file = "cytoolz-0.12.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59276021619b432a5c21c01cda8320b9cc7dbc40351ffc478b440bfccd5bbdd3"}, + {file = "cytoolz-0.12.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e44f4c25e1e7cf6149b499c74945a14649c8866d36371a2c2d2164e4649e7755"}, + {file = "cytoolz-0.12.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c64f8e60c1dd69e4d5e615481f2d57937746f4a6be2d0f86e9e7e3b9e2243b5e"}, + {file = "cytoolz-0.12.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33c63186f3bf9d7ef1347bc0537bb9a0b4111a0d7d6e619623cabc18fef0dc3b"}, + {file = "cytoolz-0.12.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fdddb9d988405f24035234f1e8d1653ab2e48cc2404226d21b49a129aefd1d25"}, + {file = "cytoolz-0.12.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6986632d8a969ea1e720990c818dace1a24c11015fd7c59b9fea0b65ef71f726"}, + {file = "cytoolz-0.12.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0ba1cbc4d9cd7571c917f88f4a069568e5121646eb5d82b2393b2cf84712cf2a"}, + {file = "cytoolz-0.12.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7d267ffc9a36c0a9a58c7e0adc9fa82620f22e4a72533e15dd1361f57fc9accf"}, + {file = "cytoolz-0.12.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95e878868a172a41fbf6c505a4b967309e6870e22adc7b1c3b19653d062711fa"}, + {file = "cytoolz-0.12.3-cp39-cp39-win32.whl", hash = "sha256:8e21932d6d260996f7109f2a40b2586070cb0a0cf1d65781e156326d5ebcc329"}, + {file = "cytoolz-0.12.3-cp39-cp39-win_amd64.whl", hash = "sha256:0d8edfbc694af6c9bda4db56643fb8ed3d14e47bec358c2f1417de9a12d6d1fb"}, + {file = "cytoolz-0.12.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:55f9bd1ae6c2a27eda5abe2a0b65a83029d2385c5a1da7b8ef47af5905d7e905"}, + {file = "cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2d271393c378282727f1231d40391ae93b93ddc0997448acc21dd0cb6a1e56d"}, + {file = "cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee98968d6a66ee83a8ceabf31182189ab5d8598998c8ce69b6d5843daeb2db60"}, + {file = "cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01cfb8518828c1189200c02a5010ea404407fb18fd5589e29c126e84bbeadd36"}, + {file = "cytoolz-0.12.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:456395d7aec01db32bf9e6db191d667347c78d8d48e77234521fa1078f60dabb"}, + {file = "cytoolz-0.12.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:cd88028bb897fba99ddd84f253ca6bef73ecb7bdf3f3cf25bc493f8f97d3c7c5"}, + {file = "cytoolz-0.12.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59b19223e7f7bd7a73ec3aa6fdfb73b579ff09c2bc0b7d26857eec2d01a58c76"}, + {file = "cytoolz-0.12.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a79d72b08048a0980a59457c239555f111ac0c8bdc140c91a025f124104dbb4"}, + {file = "cytoolz-0.12.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dd70141b32b717696a72b8876e86bc9c6f8eff995c1808e299db3541213ff82"}, + {file = "cytoolz-0.12.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:a1445c91009eb775d479e88954c51d0b4cf9a1e8ce3c503c2672d17252882647"}, + {file = "cytoolz-0.12.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ca6a9a9300d5bda417d9090107c6d2b007683efc59d63cc09aca0e7930a08a85"}, + {file = "cytoolz-0.12.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be6feb903d2a08a4ba2e70e950e862fd3be9be9a588b7c38cee4728150a52918"}, + {file = "cytoolz-0.12.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b6f43f086e5a965d33d62a145ae121b4ccb6e0789ac0acc895ce084fec8c65"}, + {file = "cytoolz-0.12.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:534fa66db8564d9b13872d81d54b6b09ae592c585eb826aac235bd6f1830f8ad"}, + {file = "cytoolz-0.12.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:fea649f979def23150680de1bd1d09682da3b54932800a0f90f29fc2a6c98ba8"}, + {file = "cytoolz-0.12.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a447247ed312dd64e3a8d9483841ecc5338ee26d6e6fbd29cd373ed030db0240"}, + {file = "cytoolz-0.12.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba3f843aa89f35467b38c398ae5b980a824fdbdb94065adc6ec7c47a0a22f4c7"}, + {file = "cytoolz-0.12.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:582c22f97a380211fb36a7b65b1beeb84ea11d82015fa84b054be78580390082"}, + {file = "cytoolz-0.12.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47feb089506fc66e1593cd9ade3945693a9d089a445fbe9a11385cab200b9f22"}, + {file = "cytoolz-0.12.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ba9002d2f043943744a9dc8e50a47362bcb6e6f360dc0a1abcb19642584d87bb"}, + {file = "cytoolz-0.12.3.tar.gz", hash = "sha256:4503dc59f4ced53a54643272c61dc305d1dbbfbd7d6bdf296948de9f34c3a282"}, ] [package.dependencies] @@ -763,78 +751,91 @@ files = [ [[package]] name = "distlib" -version = "0.3.7" +version = "0.3.8" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, - {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] [[package]] name = "dulwich" -version = "0.21.6" +version = "0.21.7" description = "Python Git Library" optional = false python-versions = ">=3.7" files = [ - {file = "dulwich-0.21.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7f89bee4c97372e8aaf8ffaf5899f1bcd5184b5306d7eaf68738c1101ceba10e"}, - {file = "dulwich-0.21.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:847bb52562a211b596453a602e75739350c86d7edb846b5b1c46896a5c86b9bb"}, - {file = "dulwich-0.21.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4e09d0b4e985b371aa6728773781b19298d361a00772e20f98522868cf7edc6f"}, - {file = "dulwich-0.21.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dfb50b3915e223a97f50fbac0dbc298d5fffeaac004eeeb3d552c57fe38416f"}, - {file = "dulwich-0.21.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a64eca1601e79c16df78afe08da9ac9497b934cbc5765990ca7d89a4b87453d9"}, - {file = "dulwich-0.21.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1fedd924763a5d640348db43a267a394aa80d551228ad45708e0b0cc2130bb62"}, - {file = "dulwich-0.21.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:edc21c3784dd9d9b85abd9fe53f81a884e2cdcc4e5e09ada17287420d64cfd46"}, - {file = "dulwich-0.21.6-cp310-cp310-win32.whl", hash = "sha256:daa3584beabfcf0da76df57535a23c80ff6d8ccde6ddbd23bdc79d317a0e20a7"}, - {file = "dulwich-0.21.6-cp310-cp310-win_amd64.whl", hash = "sha256:40623cc39a3f1634663d22d87f86e2e406cc8ff17ae7a3edc7fcf963c288992f"}, - {file = "dulwich-0.21.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e8ed878553f0b76facbb620b455fafa0943162fe8e386920717781e490444efa"}, - {file = "dulwich-0.21.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a89b19f4960e759915dbc23a4dd0abc067b55d8d65e9df50961b73091b87b81a"}, - {file = "dulwich-0.21.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28acbd08d6b38720d99cc01da9dd307a2e0585e00436c95bcac6357b9a9a6f76"}, - {file = "dulwich-0.21.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2f2683e0598f7c7071ef08a0822f062d8744549a0d45f2c156741033b7e3d7d"}, - {file = "dulwich-0.21.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54342cf96fe8a44648505c65f23d18889595762003a168d67d7263df66143bd2"}, - {file = "dulwich-0.21.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2a3fc071e5b14f164191286f7ffc02f60fe8b439d01fad0832697cc08c2237dd"}, - {file = "dulwich-0.21.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:32d7acfe3fe2ce4502446d8f7a5ab34cfd24c9ff8961e60337638410906a8fbb"}, - {file = "dulwich-0.21.6-cp311-cp311-win32.whl", hash = "sha256:5e58171a5d70f7910f73d25ff82a058edff09a4c1c3bd1de0dc6b1fbc9a42c3e"}, - {file = "dulwich-0.21.6-cp311-cp311-win_amd64.whl", hash = "sha256:ceabe8f96edfb9183034a860f5dc77586700b517457032867b64a03c44e5cf96"}, - {file = "dulwich-0.21.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4fdc2f081bc3e9e120079c2cea4be213e3f127335aca7c0ab0c19fe791270caa"}, - {file = "dulwich-0.21.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fe957564108f74325d0d042d85e0c67ef470921ca92b6e7d330c7c49a3b9c1d"}, - {file = "dulwich-0.21.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2912c8a845c8ccbc79d068a89db7172e355adeb84eb31f062cd3a406d528b30"}, - {file = "dulwich-0.21.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:81e237a6b1b20c79ef62ca19a8fb231f5519bab874b9a1c2acf9c05edcabd600"}, - {file = "dulwich-0.21.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:513d045e74307eeb31592255c38f37042c9aa68ce845a167943018ab5138b0e3"}, - {file = "dulwich-0.21.6-cp37-cp37m-win32.whl", hash = "sha256:e1ac882afa890ef993b8502647e6c6d2b3977ce56e3fe80058ce64607cbc7107"}, - {file = "dulwich-0.21.6-cp37-cp37m-win_amd64.whl", hash = "sha256:5d2ccf3d355850674f75655154a6519bf1f1664176c670109fa7041019b286f9"}, - {file = "dulwich-0.21.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:28c9724a167c84a83fc6238e0781f4702b5fe8c53ede31604525fb1a9d1833f4"}, - {file = "dulwich-0.21.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c816be529680659b6a19798287b4ec6de49040f58160d40b1b2934fd6c28e93f"}, - {file = "dulwich-0.21.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b0545f0fa9444a0eb84977d08e302e3f55fd7c34a0466ec28bedc3c839b2fc1f"}, - {file = "dulwich-0.21.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b1682e8e826471ea3c22b8521435e93799e3db8ad05dd3c8f9b1aaacfa78147"}, - {file = "dulwich-0.21.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24ad45928a65f39ea0f451f9989b7aaedba9893d48c3189b544a70c6a1043f71"}, - {file = "dulwich-0.21.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1c9e55233f19cd19c484f607cd90ab578ac50ebfef607f77e3b35c2b6049470"}, - {file = "dulwich-0.21.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:18697b58e0fc5972de68b529b08ac9ddda3f39af27bcf3f6999635ed3da7ef68"}, - {file = "dulwich-0.21.6-cp38-cp38-win32.whl", hash = "sha256:22798e9ba59e32b8faff5d9067e2b5a308f6b0fba9b1e1e928571ad278e7b36c"}, - {file = "dulwich-0.21.6-cp38-cp38-win_amd64.whl", hash = "sha256:6c91e1ed20d3d9a6aaaed9e75adae37272b3fcbcc72bab1eb09574806da88563"}, - {file = "dulwich-0.21.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8b84450766a3b151c3676fec3e3ed76304e52a84d5d69ade0f34fff2782c1b41"}, - {file = "dulwich-0.21.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3da632648ee27b64bb5b285a3a94fddf297a596891cca12ac0df43c4f59448f"}, - {file = "dulwich-0.21.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cef50c0a19f322b7150248b8fa0862ce1652dec657e340c4020573721e85f215"}, - {file = "dulwich-0.21.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ac20dfcfd6057efb8499158d23f2c059f933aefa381e192100e6d8bc25d562"}, - {file = "dulwich-0.21.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81d10aa50c0a9a6dd495990c639358e3a3bbff39e17ff302179be6e93b573da7"}, - {file = "dulwich-0.21.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a9b52a08d49731375662936d05a12c4a64a6fe0ce257111f62638e475fb5d26d"}, - {file = "dulwich-0.21.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed2f1f638b9adfba862719693b371ffe5d58e94d552ace9a23dea0fb0db6f468"}, - {file = "dulwich-0.21.6-cp39-cp39-win32.whl", hash = "sha256:bf90f2f9328a82778cf85ab696e4a7926918c3f315c75fc432ba31346bfa89b7"}, - {file = "dulwich-0.21.6-cp39-cp39-win_amd64.whl", hash = "sha256:e0dee3840c3c72e1d60c8f87a7a715d8eac023b9e1b80199d97790f7a1c60d9c"}, - {file = "dulwich-0.21.6-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:32d3a35caad6879d04711b358b861142440a543f5f4e02df67b13cbcd57f84a6"}, - {file = "dulwich-0.21.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c04df87098053b7767b46fc04b7943d75443f91c73560ca50157cdc22e27a5d3"}, - {file = "dulwich-0.21.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e07f145c7b0d82a9f77d157f493a61900e913d1c1f8b1f40d07d919ffb0929a4"}, - {file = "dulwich-0.21.6-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:008ff08629ab16d3638a9f36cfc6f5bd74b4d594657f2dc1583d8d3201794571"}, - {file = "dulwich-0.21.6-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bf469cd5076623c2aad69d01ce9d5392fcb38a5faef91abe1501be733453e37d"}, - {file = "dulwich-0.21.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6592ef2d16ac61a27022647cf64a048f5be6e0a6ab2ebc7322bfbe24fb2b971b"}, - {file = "dulwich-0.21.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99577b2b37f64bc87280079245fb2963494c345d7db355173ecec7ab3d64b949"}, - {file = "dulwich-0.21.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d7cd9fb896c65e4c28cb9332f2be192817805978dd8dc299681c4fe83c631158"}, - {file = "dulwich-0.21.6-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d9002094198e57e88fe77412d3aa64dd05978046ae725a16123ba621a7704628"}, - {file = "dulwich-0.21.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9b6f8a16f32190aa88c37ef013858b3e01964774bc983900bd0d74ecb6576e6"}, - {file = "dulwich-0.21.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee8aba4dec4d0a52737a8a141f3456229c87dcfd7961f8115786a27b6ebefed"}, - {file = "dulwich-0.21.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a780e2a0ff208c4f218e72eff8d13f9aff485ff9a6f3066c22abe4ec8cec7dcd"}, - {file = "dulwich-0.21.6.tar.gz", hash = "sha256:30fbe87e8b51f3813c131e2841c86d007434d160bd16db586b40d47f31dd05b0"}, + {file = "dulwich-0.21.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d4c0110798099bb7d36a110090f2688050703065448895c4f53ade808d889dd3"}, + {file = "dulwich-0.21.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2bc12697f0918bee324c18836053644035362bb3983dc1b210318f2fed1d7132"}, + {file = "dulwich-0.21.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:471305af74790827fcbafe330fc2e8bdcee4fb56ca1177c8c481b1c8f806c4a4"}, + {file = "dulwich-0.21.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d54c9d0e845be26f65f954dff13a1cd3f2b9739820c19064257b8fd7435ab263"}, + {file = "dulwich-0.21.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12d61334a575474e707614f2e93d6ed4cdae9eb47214f9277076d9e5615171d3"}, + {file = "dulwich-0.21.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e274cebaf345f0b1e3b70197f2651de92b652386b68020cfd3bf61bc30f6eaaa"}, + {file = "dulwich-0.21.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:817822f970e196e757ae01281ecbf21369383285b9f4a83496312204cf889b8c"}, + {file = "dulwich-0.21.7-cp310-cp310-win32.whl", hash = "sha256:7836da3f4110ce684dcd53489015fb7fa94ed33c5276e3318b8b1cbcb5b71e08"}, + {file = "dulwich-0.21.7-cp310-cp310-win_amd64.whl", hash = "sha256:4a043b90958cec866b4edc6aef5fe3c2c96a664d0b357e1682a46f6c477273c4"}, + {file = "dulwich-0.21.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ce8db196e79c1f381469410d26fb1d8b89c6b87a4e7f00ff418c22a35121405c"}, + {file = "dulwich-0.21.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:62bfb26bdce869cd40be443dfd93143caea7089b165d2dcc33de40f6ac9d812a"}, + {file = "dulwich-0.21.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c01a735b9a171dcb634a97a3cec1b174cfbfa8e840156870384b633da0460f18"}, + {file = "dulwich-0.21.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa4d14767cf7a49c9231c2e52cb2a3e90d0c83f843eb6a2ca2b5d81d254cf6b9"}, + {file = "dulwich-0.21.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bca4b86e96d6ef18c5bc39828ea349efb5be2f9b1f6ac9863f90589bac1084d"}, + {file = "dulwich-0.21.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a7b5624b02ef808cdc62dabd47eb10cd4ac15e8ac6df9e2e88b6ac6b40133673"}, + {file = "dulwich-0.21.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c3a539b4696a42fbdb7412cb7b66a4d4d332761299d3613d90a642923c7560e1"}, + {file = "dulwich-0.21.7-cp311-cp311-win32.whl", hash = "sha256:675a612ce913081beb0f37b286891e795d905691dfccfb9bf73721dca6757cde"}, + {file = "dulwich-0.21.7-cp311-cp311-win_amd64.whl", hash = "sha256:460ba74bdb19f8d498786ae7776745875059b1178066208c0fd509792d7f7bfc"}, + {file = "dulwich-0.21.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4c51058ec4c0b45dc5189225b9e0c671b96ca9713c1daf71d622c13b0ab07681"}, + {file = "dulwich-0.21.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4bc4c5366eaf26dda3fdffe160a3b515666ed27c2419f1d483da285ac1411de0"}, + {file = "dulwich-0.21.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a0650ec77d89cb947e3e4bbd4841c96f74e52b4650830112c3057a8ca891dc2f"}, + {file = "dulwich-0.21.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f18f0a311fb7734b033a3101292b932158cade54b74d1c44db519e42825e5a2"}, + {file = "dulwich-0.21.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c589468e5c0cd84e97eb7ec209ab005a2cb69399e8c5861c3edfe38989ac3a8"}, + {file = "dulwich-0.21.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d62446797163317a397a10080c6397ffaaca51a7804c0120b334f8165736c56a"}, + {file = "dulwich-0.21.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e84cc606b1f581733df4350ca4070e6a8b30be3662bbb81a590b177d0c996c91"}, + {file = "dulwich-0.21.7-cp312-cp312-win32.whl", hash = "sha256:c3d1685f320907a52c40fd5890627945c51f3a5fa4bcfe10edb24fec79caadec"}, + {file = "dulwich-0.21.7-cp312-cp312-win_amd64.whl", hash = "sha256:6bd69921fdd813b7469a3c77bc75c1783cc1d8d72ab15a406598e5a3ba1a1503"}, + {file = "dulwich-0.21.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d8ab29c660125db52106775caa1f8f7f77a69ed1fe8bc4b42bdf115731a25bf"}, + {file = "dulwich-0.21.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0d2e4485b98695bf95350ce9d38b1bb0aaac2c34ad00a0df789aa33c934469b"}, + {file = "dulwich-0.21.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e138d516baa6b5bafbe8f030eccc544d0d486d6819b82387fc0e285e62ef5261"}, + {file = "dulwich-0.21.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f34bf9b9fa9308376263fd9ac43143c7c09da9bc75037bb75c6c2423a151b92c"}, + {file = "dulwich-0.21.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e2c66888207b71cd1daa2acb06d3984a6bc13787b837397a64117aa9fc5936a"}, + {file = "dulwich-0.21.7-cp37-cp37m-win32.whl", hash = "sha256:10893105c6566fc95bc2a67b61df7cc1e8f9126d02a1df6a8b2b82eb59db8ab9"}, + {file = "dulwich-0.21.7-cp37-cp37m-win_amd64.whl", hash = "sha256:460b3849d5c3d3818a80743b4f7a0094c893c559f678e56a02fff570b49a644a"}, + {file = "dulwich-0.21.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74700e4c7d532877355743336c36f51b414d01e92ba7d304c4f8d9a5946dbc81"}, + {file = "dulwich-0.21.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c92e72c43c9e9e936b01a57167e0ea77d3fd2d82416edf9489faa87278a1cdf7"}, + {file = "dulwich-0.21.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d097e963eb6b9fa53266146471531ad9c6765bf390849230311514546ed64db2"}, + {file = "dulwich-0.21.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:808e8b9cc0aa9ac74870b49db4f9f39a52fb61694573f84b9c0613c928d4caf8"}, + {file = "dulwich-0.21.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1957b65f96e36c301e419d7adaadcff47647c30eb072468901bb683b1000bc5"}, + {file = "dulwich-0.21.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4b09bc3a64fb70132ec14326ecbe6e0555381108caff3496898962c4136a48c6"}, + {file = "dulwich-0.21.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5882e70b74ac3c736a42d3fdd4f5f2e6570637f59ad5d3e684760290b58f041"}, + {file = "dulwich-0.21.7-cp38-cp38-win32.whl", hash = "sha256:29bb5c1d70eba155ded41ed8a62be2f72edbb3c77b08f65b89c03976292f6d1b"}, + {file = "dulwich-0.21.7-cp38-cp38-win_amd64.whl", hash = "sha256:25c3ab8fb2e201ad2031ddd32e4c68b7c03cb34b24a5ff477b7a7dcef86372f5"}, + {file = "dulwich-0.21.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8929c37986c83deb4eb500c766ee28b6670285b512402647ee02a857320e377c"}, + {file = "dulwich-0.21.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc1e11be527ac06316539b57a7688bcb1b6a3e53933bc2f844397bc50734e9ae"}, + {file = "dulwich-0.21.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fc3078a1ba04c588fabb0969d3530efd5cd1ce2cf248eefb6baf7cbc15fc285"}, + {file = "dulwich-0.21.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dcbd29ba30ba2c5bfbab07a61a5f20095541d5ac66d813056c122244df4ac0"}, + {file = "dulwich-0.21.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8869fc8ec3dda743e03d06d698ad489b3705775fe62825e00fa95aa158097fc0"}, + {file = "dulwich-0.21.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d96ca5e0dde49376fbcb44f10eddb6c30284a87bd03bb577c59bb0a1f63903fa"}, + {file = "dulwich-0.21.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0064363bd5e814359657ae32517fa8001e8573d9d040bd997908d488ab886ed"}, + {file = "dulwich-0.21.7-cp39-cp39-win32.whl", hash = "sha256:869eb7be48243e695673b07905d18b73d1054a85e1f6e298fe63ba2843bb2ca1"}, + {file = "dulwich-0.21.7-cp39-cp39-win_amd64.whl", hash = "sha256:404b8edeb3c3a86c47c0a498699fc064c93fa1f8bab2ffe919e8ab03eafaaad3"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e598d743c6c0548ebcd2baf94aa9c8bfacb787ea671eeeb5828cfbd7d56b552f"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a2d76c96426e791556836ef43542b639def81be4f1d6d4322cd886c115eae1"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6c88acb60a1f4d31bd6d13bfba465853b3df940ee4a0f2a3d6c7a0778c705b7"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ecd315847dea406a4decfa39d388a2521e4e31acde3bd9c2609c989e817c6d62"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d05d3c781bc74e2c2a2a8f4e4e2ed693540fbe88e6ac36df81deac574a6dad99"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6de6f8de4a453fdbae8062a6faa652255d22a3d8bce0cd6d2d6701305c75f2b3"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e25953c7acbbe4e19650d0225af1c0c0e6882f8bddd2056f75c1cc2b109b88ad"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:4637cbd8ed1012f67e1068aaed19fcc8b649bcf3e9e26649826a303298c89b9d"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:858842b30ad6486aacaa607d60bab9c9a29e7c59dc2d9cb77ae5a94053878c08"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:739b191f61e1c4ce18ac7d520e7a7cbda00e182c3489552408237200ce8411ad"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:274c18ec3599a92a9b67abaf110e4f181a4f779ee1aaab9e23a72e89d71b2bd9"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2590e9b431efa94fc356ae33b38f5e64f1834ec3a94a6ac3a64283b206d07aa3"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed60d1f610ef6437586f7768254c2a93820ccbd4cfdac7d182cf2d6e615969bb"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8278835e168dd097089f9e53088c7a69c6ca0841aef580d9603eafe9aea8c358"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffc27fb063f740712e02b4d2f826aee8bbed737ed799962fef625e2ce56e2d29"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:61e3451bd3d3844f2dca53f131982553be4d1b1e1ebd9db701843dd76c4dba31"}, + {file = "dulwich-0.21.7.tar.gz", hash = "sha256:a9e9c66833cea580c3ac12927e4b9711985d76afca98da971405d414de60e968"}, ] [package.dependencies] @@ -848,18 +849,18 @@ pgp = ["gpg"] [[package]] name = "eip712" -version = "0.2.1" +version = "0.2.2" description = "eip712: Message classes for typed structured data hashing and signing in Ethereum" optional = false python-versions = ">=3.8,<4" files = [ - {file = "eip712-0.2.1-py3-none-any.whl", hash = "sha256:c984c577358d1c7e5d4e52802bf4bd0432e965ba7326448998f95fcc1b6d5269"}, - {file = "eip712-0.2.1.tar.gz", hash = "sha256:3997dace7e581b66a84d106a10baac47a3f6c94095d79c7d0971ca0ede1926ad"}, + {file = "eip712-0.2.2-py3-none-any.whl", hash = "sha256:576476dd1d276e444a633ac22ab25209e18f8f41e5016e576a132d190043a4ba"}, + {file = "eip712-0.2.2.tar.gz", hash = "sha256:6d2e07a83c66fb1cbe2448bb4dfea1c91913c4822b7d9b89231e5b61473ae426"}, ] [package.dependencies] dataclassy = ">=0.8.2,<1" -eth-abi = ">=4.0.0,<5" +eth-abi = ">=4.1.0,<5" eth-account = ">=0.8.0,<0.9" eth-hash = {version = "*", extras = ["pycryptodome"]} eth-typing = ">=3.3.0,<4" @@ -867,9 +868,9 @@ eth-utils = ">=2.1.0,<3" hexbytes = ">=0.3.0,<1" [package.extras] -dev = ["IPython", "Sphinx (>=5.3.0,<6)", "black (>=23.1.0,<24)", "commitizen (>=2.42,<3)", "flake8 (>=6.0.0,<7)", "hypothesis (>=6.70.0,<7)", "ipdb", "isort (>=5.12.0,<6)", "mdformat (>=0.7.16,<0.8)", "mdformat-frontmatter (>=0.4.1,<0.5)", "mdformat-gfm (>=0.3.5,<0.4)", "mypy (>=1.1.1,<2)", "myst-parser (>=0.18.1,<0.19)", "pre-commit", "pytest (>=6.0,<8)", "pytest-cov", "pytest-watch", "pytest-xdist", "setuptools", "sphinx-rtd-theme (>=1.2.0,<2)", "sphinxcontrib-napoleon (>=0.7)", "twine", "types-setuptools", "wheel"] +dev = ["IPython", "Sphinx (>=5.3.0,<6)", "black (>=23.7.0,<24)", "commitizen (>=2.42,<3)", "flake8 (>=6.0.0,<7)", "hypothesis (>=6.70.0,<7)", "ipdb", "isort (>=5.12.0,<6)", "mdformat (>=0.7.16,<0.8)", "mdformat-frontmatter (>=0.4.1,<0.5)", "mdformat-gfm (>=0.3.5,<0.4)", "mypy (>=1.5.1,<2)", "myst-parser (>=0.18.1,<0.19)", "pre-commit", "pytest (>=6.0,<8)", "pytest-cov", "pytest-watch", "pytest-xdist", "setuptools", "sphinx-rtd-theme (>=1.2.0,<2)", "sphinxcontrib-napoleon (>=0.7)", "twine", "types-setuptools", "wheel"] doc = ["Sphinx (>=5.3.0,<6)", "myst-parser (>=0.18.1,<0.19)", "sphinx-rtd-theme (>=1.2.0,<2)", "sphinxcontrib-napoleon (>=0.7)"] -lint = ["black (>=23.1.0,<24)", "flake8 (>=6.0.0,<7)", "isort (>=5.12.0,<6)", "mdformat (>=0.7.16,<0.8)", "mdformat-frontmatter (>=0.4.1,<0.5)", "mdformat-gfm (>=0.3.5,<0.4)", "mypy (>=1.1.1,<2)", "types-setuptools"] +lint = ["black (>=23.7.0,<24)", "flake8 (>=6.0.0,<7)", "isort (>=5.12.0,<6)", "mdformat (>=0.7.16,<0.8)", "mdformat-frontmatter (>=0.4.1,<0.5)", "mdformat-gfm (>=0.3.5,<0.4)", "mypy (>=1.5.1,<2)", "types-setuptools"] release = ["setuptools", "twine", "wheel"] test = ["hypothesis (>=6.70.0,<7)", "pytest (>=6.0,<8)", "pytest-cov", "pytest-xdist"] @@ -925,42 +926,40 @@ test = ["coverage", "hypothesis (>=4.18.0,<5)", "pytest (>=6.2.5,<7)", "pytest-x [[package]] name = "eth-bloom" -version = "2.0.0" -description = "Python implementation of the Ethereum Trie structure" +version = "3.0.0" +description = "A python implementation of the bloom filter used by Ethereum" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.8, <4" files = [ - {file = "eth-bloom-2.0.0.tar.gz", hash = "sha256:73576828dff7566b9216403e0898966912f370bae5734241dd3f50ce5664a825"}, - {file = "eth_bloom-2.0.0-py3-none-any.whl", hash = "sha256:cc86ab9670577996f7fcb8445b7a164ecd211ac91d9c4c2b5a47678623419927"}, + {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] -deploy = ["bumpversion", "wheel"] -dev = ["black (>=22.1.0)", "build", "bumpversion", "flake8 (>=3.8.3)", "hypothesis (>=3.31.2)", "isort (>=4.2.15)", "mypy (==0.910)", "pytest (>=6.2.5)", "tox (>=2.6.0)", "twine", "wheel"] -lint = ["black (>=22.1.0)", "flake8 (>=3.8.3)", "isort (>=4.2.15)", "mypy (==0.910)"] -test = ["hypothesis (>=3.31.2)", "pytest (>=6.2.5)", "tox (>=2.6.0)"] +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.5.2" +version = "0.6.0" description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.8, <4" files = [ - {file = "eth-hash-0.5.2.tar.gz", hash = "sha256:1b5f10eca7765cc385e1430eefc5ced6e2e463bb18d1365510e2e539c1a6fe4e"}, - {file = "eth_hash-0.5.2-py3-none-any.whl", hash = "sha256:251f62f6579a1e247561679d78df37548bd5f59908da0b159982bf8293ad32f0"}, + {file = "eth-hash-0.6.0.tar.gz", hash = "sha256:ae72889e60db6acbb3872c288cfa02ed157f4c27630fcd7f9c8442302c31e478"}, + {file = "eth_hash-0.6.0-py3-none-any.whl", hash = "sha256:9f8daaa345764f8871dc461855049ac54ae4291d780279bce6fce7f24e3f17d3"}, ] [package.dependencies] pycryptodome = {version = ">=3.6.6,<4", optional = true, markers = "extra == \"pycryptodome\""} [package.extras] -dev = ["black (>=23)", "build (>=0.9.0)", "bumpversion (>=0.5.3)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "ipython", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)", "pytest (>=7.0.0)", "pytest-watch (>=4.1.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"] -doc = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -lint = ["black (>=23)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)"] +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)"] pycryptodome = ["pycryptodome (>=3.6.6,<4)"] pysha3 = ["pysha3 (>=1.0.0,<2.0.0)", "safe-pysha3 (>=1.0.0)"] test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] @@ -1050,33 +1049,33 @@ hypothesis = ["hypothesis (>=6.58.0,<7.0.0)"] [[package]] name = "eth-typing" -version = "3.5.0" +version = "3.5.2" description = "eth-typing: Common type annotations for ethereum python packages" optional = false python-versions = ">=3.7.2, <4" files = [ - {file = "eth-typing-3.5.0.tar.gz", hash = "sha256:a92f6896896752143a4704c57441eedf7b1f65d5df4b1c20cb802bb4aa602d7e"}, - {file = "eth_typing-3.5.0-py3-none-any.whl", hash = "sha256:a773dbb7d78fcd1539c30264193ca26ec965f3abca2711748e307f117b0a10f5"}, + {file = "eth-typing-3.5.2.tar.gz", hash = "sha256:22bf051ddfaa35ff827c30090de167e5c5b8cc6d343f7f35c9b1c7553f6ab64d"}, + {file = "eth_typing-3.5.2-py3-none-any.whl", hash = "sha256:1842e628fb1ffa929b94f89a9d33caafbeb9978dc96abb6036a12bc91f1c624b"}, ] [package.dependencies] typing-extensions = ">=4.0.1" [package.extras] -dev = ["black (>=23)", "build (>=0.9.0)", "bumpversion (>=0.5.3)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "ipython", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)", "pytest (>=7.0.0)", "pytest-watch (>=4.1.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +dev = ["black (>=23)", "build (>=0.9.0)", "bumpversion (>=0.5.3)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "ipython", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)", "pytest (>=7.0.0)", "pytest-watch (>=4.1.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "types-setuptools", "wheel"] docs = ["sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -lint = ["black (>=23)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)"] +lint = ["black (>=23)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)", "types-setuptools"] test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-utils" -version = "2.2.2" +version = "2.3.1" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" optional = false python-versions = ">=3.7,<4" files = [ - {file = "eth-utils-2.2.2.tar.gz", hash = "sha256:5ca6265177ce544d9d43cdf2272ae2227e5d6d9529c270bbb707d17339087101"}, - {file = "eth_utils-2.2.2-py3-none-any.whl", hash = "sha256:2580a8065273f62ca1ec4c175228c52e626a5f1007e965d2117e5eca1a93cae8"}, + {file = "eth-utils-2.3.1.tar.gz", hash = "sha256:56a969b0536d4969dcb27e580521de35abf2dbed8b1bf072b5c80770c4324e27"}, + {file = "eth_utils-2.3.1-py3-none-any.whl", hash = "sha256:614eedc5ffcaf4e6708ca39e23b12bd69526a312068c1170c773bd1307d13972"}, ] [package.dependencies] @@ -1093,13 +1092,13 @@ test = ["hypothesis (>=4.43.0)", "mypy (==0.971)", "pytest (>=7.0.0)", "pytest-x [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -1121,13 +1120,13 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "executing" -version = "2.0.0" +version = "2.0.1" description = "Get the currently executing AST node of a frame, and other information" optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "executing-2.0.0-py2.py3-none-any.whl", hash = "sha256:06df6183df67389625f4e763921c6cf978944721abf3e714000200aab95b0657"}, - {file = "executing-2.0.0.tar.gz", hash = "sha256:0ff053696fdeef426cda5bd18eacd94f82c91f49823a2e9090124212ceea9b08"}, + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, ] [package.extras] @@ -1150,19 +1149,19 @@ pyrepl = ">=0.8.2" [[package]] name = "filelock" -version = "3.12.4" +version = "3.13.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, - {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] -typing = ["typing-extensions (>=4.7.1)"] +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)"] +typing = ["typing-extensions (>=4.8)"] [[package]] name = "flake8" @@ -1220,22 +1219,22 @@ lxml = ["lxml"] [[package]] name = "hypothesis" -version = "6.88.0" +version = "6.97.3" description = "A library for property-based testing" optional = false python-versions = ">=3.8" files = [ - {file = "hypothesis-6.88.0-py3-none-any.whl", hash = "sha256:b52b5b5a5065340875fb8a1a45e45391c277d9c5765374560edc1c5e5c3e2d48"}, - {file = "hypothesis-6.88.0.tar.gz", hash = "sha256:c9096ccd5a78bbf75221a2b4a6149e00e254acb17637c94abab98c529b2f61e5"}, + {file = "hypothesis-6.97.3-py3-none-any.whl", hash = "sha256:6256d768ec866426bfce6ed78418c6e3e43119a0dbece2e0229a1ae5929ae53d"}, + {file = "hypothesis-6.97.3.tar.gz", hash = "sha256:00216ddadaee17ba73451e262f973970a97d34fd75ec34ef57510147264c34d1"}, ] [package.dependencies] -attrs = ">=19.2.0" +attrs = ">=22.2.0" exceptiongroup = {version = ">=1.0.0", markers = "python_version < \"3.11\""} sortedcontainers = ">=2.1.0,<3.0.0" [package.extras] -all = ["backports.zoneinfo (>=0.2.1)", "black (>=19.10b0)", "click (>=7.0)", "django (>=3.2)", "dpcontracts (>=0.4)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.17.3)", "pandas (>=1.1)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2023.3)"] +all = ["backports.zoneinfo (>=0.2.1)", "black (>=19.10b0)", "click (>=7.0)", "django (>=3.2)", "dpcontracts (>=0.4)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.17.3)", "pandas (>=1.1)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2023.4)"] cli = ["black (>=19.10b0)", "click (>=7.0)", "rich (>=9.0.0)"] codemods = ["libcst (>=0.3.16)"] dateutil = ["python-dateutil (>=1.4)"] @@ -1248,17 +1247,17 @@ pandas = ["pandas (>=1.1)"] pytest = ["pytest (>=4.6)"] pytz = ["pytz (>=2014.1)"] redis = ["redis (>=3.0.0)"] -zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2023.3)"] +zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2023.4)"] [[package]] name = "identify" -version = "2.5.30" +version = "2.5.33" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.30-py2.py3-none-any.whl", hash = "sha256:afe67f26ae29bab007ec21b03d4114f41316ab9dd15aa8736a167481e108da54"}, - {file = "identify-2.5.30.tar.gz", hash = "sha256:f302a4256a15c849b91cfcdcec052a8ce914634b2f77ae87dad29cd749f2d88d"}, + {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, + {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, ] [package.extras] @@ -1266,31 +1265,31 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] name = "importlib-metadata" -version = "6.8.0" +version = "7.0.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, - {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, + {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, + {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] @@ -1318,42 +1317,39 @@ files = [ [[package]] name = "ipython" -version = "8.16.1" +version = "8.21.0" description = "IPython: Productive Interactive Computing" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "ipython-8.16.1-py3-none-any.whl", hash = "sha256:0852469d4d579d9cd613c220af7bf0c9cc251813e12be647cb9d463939db9b1e"}, - {file = "ipython-8.16.1.tar.gz", hash = "sha256:ad52f58fca8f9f848e256c629eff888efc0528c12fe0f8ec14f33205f23ef938"}, + {file = "ipython-8.21.0-py3-none-any.whl", hash = "sha256:1050a3ab8473488d7eee163796b02e511d0735cf43a04ba2a8348bd0f2eaf8a5"}, + {file = "ipython-8.21.0.tar.gz", hash = "sha256:48fbc236fbe0e138b88773fa0437751f14c3645fb483f1d4c5dee58b37e5ce73"}, ] [package.dependencies] -appnope = {version = "*", markers = "sys_platform == \"darwin\""} -backcall = "*" colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -pickleshare = "*" -prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5" [package.extras] -all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.23)", "pandas", "pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test = ["pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "pickleshare", "pytest (<8)", "pytest-asyncio (<0.22)", "testpath", "trio"] [[package]] name = "isort" @@ -1426,13 +1422,13 @@ trio = ["async_generator", "trio"] [[package]] name = "jsonschema" -version = "4.19.1" +version = "4.21.1" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema-4.19.1-py3-none-any.whl", hash = "sha256:cd5f1f9ed9444e554b38ba003af06c0a8c2868131e56bfbef0550fb450c0330e"}, - {file = "jsonschema-4.19.1.tar.gz", hash = "sha256:ec84cc37cfa703ef7cd4928db24f9cb31428a5d0fa77747b8b51a847458e0bbf"}, + {file = "jsonschema-4.21.1-py3-none-any.whl", hash = "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f"}, + {file = "jsonschema-4.21.1.tar.gz", hash = "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5"}, ] [package.dependencies] @@ -1447,17 +1443,17 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jsonschema-specifications" -version = "2023.7.1" +version = "2023.12.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema_specifications-2023.7.1-py3-none-any.whl", hash = "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1"}, - {file = "jsonschema_specifications-2023.7.1.tar.gz", hash = "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb"}, + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, ] [package.dependencies] -referencing = ">=0.28.0" +referencing = ">=0.31.0" [[package]] name = "keyring" @@ -1484,13 +1480,13 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec [[package]] name = "lark" -version = "1.1.7" +version = "1.1.9" description = "a modern parsing library" optional = false python-versions = ">=3.6" files = [ - {file = "lark-1.1.7-py3-none-any.whl", hash = "sha256:9e5dc5bbf93fa1840083707285262514a0ef8a6613874af7ea1cec60468d6e92"}, - {file = "lark-1.1.7.tar.gz", hash = "sha256:be7437bf1f37ab08b355f29ff2571d77d777113d0a8c4352b0c513dced6c5a1e"}, + {file = "lark-1.1.9-py3-none-any.whl", hash = "sha256:a0dd3a87289f8ccbb325901e4222e723e7d745dbfc1803eaf5f3d2ace19cf2db"}, + {file = "lark-1.1.9.tar.gz", hash = "sha256:15fa5236490824c2c4aba0e22d2d6d823575dcaf4cdd1848e34b6ad836240fba"}, ] [package.extras] @@ -1512,93 +1508,92 @@ files = [ [[package]] name = "lru-dict" -version = "1.2.0" +version = "1.3.0" description = "An Dict like LRU container." optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "lru-dict-1.2.0.tar.gz", hash = "sha256:13c56782f19d68ddf4d8db0170041192859616514c706b126d0df2ec72a11bd7"}, - {file = "lru_dict-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:de906e5486b5c053d15b7731583c25e3c9147c288ac8152a6d1f9bccdec72641"}, - {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604d07c7604b20b3130405d137cae61579578b0e8377daae4125098feebcb970"}, - {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:203b3e78d03d88f491fa134f85a42919020686b6e6f2d09759b2f5517260c651"}, - {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:020b93870f8c7195774cbd94f033b96c14f51c57537969965c3af300331724fe"}, - {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1184d91cfebd5d1e659d47f17a60185bbf621635ca56dcdc46c6a1745d25df5c"}, - {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fc42882b554a86e564e0b662da47b8a4b32fa966920bd165e27bb8079a323bc1"}, - {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:18ee88ada65bd2ffd483023be0fa1c0a6a051ef666d1cd89e921dcce134149f2"}, - {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:756230c22257597b7557eaef7f90484c489e9ba78e5bb6ab5a5bcfb6b03cb075"}, - {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c4da599af36618881748b5db457d937955bb2b4800db891647d46767d636c408"}, - {file = "lru_dict-1.2.0-cp310-cp310-win32.whl", hash = "sha256:35a142a7d1a4fd5d5799cc4f8ab2fff50a598d8cee1d1c611f50722b3e27874f"}, - {file = "lru_dict-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:6da5b8099766c4da3bf1ed6e7d7f5eff1681aff6b5987d1258a13bd2ed54f0c9"}, - {file = "lru_dict-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b20b7c9beb481e92e07368ebfaa363ed7ef61e65ffe6e0edbdbaceb33e134124"}, - {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22147367b296be31cc858bf167c448af02435cac44806b228c9be8117f1bfce4"}, - {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34a3091abeb95e707f381a8b5b7dc8e4ee016316c659c49b726857b0d6d1bd7a"}, - {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:877801a20f05c467126b55338a4e9fa30e2a141eb7b0b740794571b7d619ee11"}, - {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d3336e901acec897bcd318c42c2b93d5f1d038e67688f497045fc6bad2c0be7"}, - {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8dafc481d2defb381f19b22cc51837e8a42631e98e34b9e0892245cc96593deb"}, - {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:87bbad3f5c3de8897b8c1263a9af73bbb6469fb90e7b57225dad89b8ef62cd8d"}, - {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:25f9e0bc2fe8f41c2711ccefd2871f8a5f50a39e6293b68c3dec576112937aad"}, - {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ae301c282a499dc1968dd633cfef8771dd84228ae9d40002a3ea990e4ff0c469"}, - {file = "lru_dict-1.2.0-cp311-cp311-win32.whl", hash = "sha256:c9617583173a29048e11397f165501edc5ae223504a404b2532a212a71ecc9ed"}, - {file = "lru_dict-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6b7a031e47421d4b7aa626b8c91c180a9f037f89e5d0a71c4bb7afcf4036c774"}, - {file = "lru_dict-1.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ea2ac3f7a7a2f32f194c84d82a034e66780057fd908b421becd2f173504d040e"}, - {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd46c94966f631a81ffe33eee928db58e9fbee15baba5923d284aeadc0e0fa76"}, - {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:086ce993414f0b28530ded7e004c77dc57c5748fa6da488602aa6e7f79e6210e"}, - {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df25a426446197488a6702954dcc1de511deee20c9db730499a2aa83fddf0df1"}, - {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c53b12b89bd7a6c79f0536ff0d0a84fdf4ab5f6252d94b24b9b753bd9ada2ddf"}, - {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f9484016e6765bd295708cccc9def49f708ce07ac003808f69efa386633affb9"}, - {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d0f7ec902a0097ac39f1922c89be9eaccf00eb87751e28915320b4f72912d057"}, - {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:981ef3edc82da38d39eb60eae225b88a538d47b90cce2e5808846fd2cf64384b"}, - {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e25b2e90a032dc248213af7f3f3e975e1934b204f3b16aeeaeaff27a3b65e128"}, - {file = "lru_dict-1.2.0-cp36-cp36m-win32.whl", hash = "sha256:59f3df78e94e07959f17764e7fa7ca6b54e9296953d2626a112eab08e1beb2db"}, - {file = "lru_dict-1.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:de24b47159e07833aeab517d9cb1c3c5c2d6445cc378b1c2f1d8d15fb4841d63"}, - {file = "lru_dict-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d0dd4cd58220351233002f910e35cc01d30337696b55c6578f71318b137770f9"}, - {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a87bdc291718bbdf9ea4be12ae7af26cbf0706fa62c2ac332748e3116c5510a7"}, - {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05fb8744f91f58479cbe07ed80ada6696ec7df21ea1740891d4107a8dd99a970"}, - {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00f6e8a3fc91481b40395316a14c94daa0f0a5de62e7e01a7d589f8d29224052"}, - {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b172fce0a0ffc0fa6d282c14256d5a68b5db1e64719c2915e69084c4b6bf555"}, - {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e707d93bae8f0a14e6df1ae8b0f076532b35f00e691995f33132d806a88e5c18"}, - {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b9ec7a4a0d6b8297102aa56758434fb1fca276a82ed7362e37817407185c3abb"}, - {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f404dcc8172da1f28da9b1f0087009578e608a4899b96d244925c4f463201f2a"}, - {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1171ad3bff32aa8086778be4a3bdff595cc2692e78685bcce9cb06b96b22dcc2"}, - {file = "lru_dict-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:0c316dfa3897fabaa1fe08aae89352a3b109e5f88b25529bc01e98ac029bf878"}, - {file = "lru_dict-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5919dd04446bc1ee8d6ecda2187deeebfff5903538ae71083e069bc678599446"}, - {file = "lru_dict-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbf36c5a220a85187cacc1fcb7dd87070e04b5fc28df7a43f6842f7c8224a388"}, - {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712e71b64da181e1c0a2eaa76cd860265980cd15cb0e0498602b8aa35d5db9f8"}, - {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f54908bf91280a9b8fa6a8c8f3c2f65850ce6acae2852bbe292391628ebca42f"}, - {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3838e33710935da2ade1dd404a8b936d571e29268a70ff4ca5ba758abb3850df"}, - {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5d5a5f976b39af73324f2b793862859902ccb9542621856d51a5993064f25e4"}, - {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8bda3a9afd241ee0181661decaae25e5336ce513ac268ab57da737eacaa7871f"}, - {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bd2cd1b998ea4c8c1dad829fc4fa88aeed4dee555b5e03c132fc618e6123f168"}, - {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b55753ee23028ba8644fd22e50de7b8f85fa60b562a0fafaad788701d6131ff8"}, - {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e51fa6a203fa91d415f3b2900e5748ec8e06ad75777c98cc3aeb3983ca416d7"}, - {file = "lru_dict-1.2.0-cp38-cp38-win32.whl", hash = "sha256:cd6806313606559e6c7adfa0dbeb30fc5ab625f00958c3d93f84831e7a32b71e"}, - {file = "lru_dict-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d90a70c53b0566084447c3ef9374cc5a9be886e867b36f89495f211baabd322"}, - {file = "lru_dict-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3ea7571b6bf2090a85ff037e6593bbafe1a8598d5c3b4560eb56187bcccb4dc"}, - {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:287c2115a59c1c9ed0d5d8ae7671e594b1206c36ea9df2fca6b17b86c468ff99"}, - {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5ccfd2291c93746a286c87c3f895165b697399969d24c54804ec3ec559d4e43"}, - {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b710f0f4d7ec4f9fa89dfde7002f80bcd77de8024017e70706b0911ea086e2ef"}, - {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5345bf50e127bd2767e9fd42393635bbc0146eac01f6baf6ef12c332d1a6a329"}, - {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:291d13f85224551913a78fe695cde04cbca9dcb1d84c540167c443eb913603c9"}, - {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d5bb41bc74b321789803d45b124fc2145c1b3353b4ad43296d9d1d242574969b"}, - {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0facf49b053bf4926d92d8d5a46fe07eecd2af0441add0182c7432d53d6da667"}, - {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:987b73a06bcf5a95d7dc296241c6b1f9bc6cda42586948c9dabf386dc2bef1cd"}, - {file = "lru_dict-1.2.0-cp39-cp39-win32.whl", hash = "sha256:231d7608f029dda42f9610e5723614a35b1fff035a8060cf7d2be19f1711ace8"}, - {file = "lru_dict-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:71da89e134747e20ed5b8ad5b4ee93fc5b31022c2b71e8176e73c5a44699061b"}, - {file = "lru_dict-1.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:21b3090928c7b6cec509e755cc3ab742154b33660a9b433923bd12c37c448e3e"}, - {file = "lru_dict-1.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaecd7085212d0aa4cd855f38b9d61803d6509731138bf798a9594745953245b"}, - {file = "lru_dict-1.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ead83ac59a29d6439ddff46e205ce32f8b7f71a6bd8062347f77e232825e3d0a"}, - {file = "lru_dict-1.2.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:312b6b2a30188586fe71358f0f33e4bac882d33f5e5019b26f084363f42f986f"}, - {file = "lru_dict-1.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b30122e098c80e36d0117810d46459a46313421ce3298709170b687dc1240b02"}, - {file = "lru_dict-1.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f010cfad3ab10676e44dc72a813c968cd586f37b466d27cde73d1f7f1ba158c2"}, - {file = "lru_dict-1.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20f5f411f7751ad9a2c02e80287cedf69ae032edd321fe696e310d32dd30a1f8"}, - {file = "lru_dict-1.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:afdadd73304c9befaed02eb42f5f09fdc16288de0a08b32b8080f0f0f6350aa6"}, - {file = "lru_dict-1.2.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7ab0c10c4fa99dc9e26b04e6b62ac32d2bcaea3aad9b81ec8ce9a7aa32b7b1b"}, - {file = "lru_dict-1.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:edad398d5d402c43d2adada390dd83c74e46e020945ff4df801166047013617e"}, - {file = "lru_dict-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:91d577a11b84387013815b1ad0bb6e604558d646003b44c92b3ddf886ad0f879"}, - {file = "lru_dict-1.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb12f19cdf9c4f2d9aa259562e19b188ff34afab28dd9509ff32a3f1c2c29326"}, - {file = "lru_dict-1.2.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e4c85aa8844bdca3c8abac3b7f78da1531c74e9f8b3e4890c6e6d86a5a3f6c0"}, - {file = "lru_dict-1.2.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c6acbd097b15bead4de8e83e8a1030bb4d8257723669097eac643a301a952f0"}, - {file = "lru_dict-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b6613daa851745dd22b860651de930275be9d3e9373283a2164992abacb75b62"}, + {file = "lru-dict-1.3.0.tar.gz", hash = "sha256:54fd1966d6bd1fcde781596cb86068214edeebff1db13a2cea11079e3fd07b6b"}, + {file = "lru_dict-1.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4073333894db9840f066226d50e6f914a2240711c87d60885d8c940b69a6673f"}, + {file = "lru_dict-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0ad6361e4dd63b47b2fc8eab344198f37387e1da3dcfacfee19bafac3ec9f1eb"}, + {file = "lru_dict-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c637ab54b8cd9802fe19b260261e38820d748adf7606e34045d3c799b6dde813"}, + {file = "lru_dict-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fce5f95489ca1fc158cc9fe0f4866db9cec82c2be0470926a9080570392beaf"}, + {file = "lru_dict-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2bf2e24cf5f19c3ff69bf639306e83dced273e6fa775b04e190d7f5cd16f794"}, + {file = "lru_dict-1.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e90059f7701bef3c4da073d6e0434a9c7dc551d5adce30e6b99ef86b186f4b4a"}, + {file = "lru_dict-1.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ecb7ae557239c64077e9b26a142eb88e63cddb104111a5122de7bebbbd00098"}, + {file = "lru_dict-1.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6af36166d22dba851e06a13e35bbf33845d3dd88872e6aebbc8e3e7db70f4682"}, + {file = "lru_dict-1.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ee38d420c77eed548df47b7d74b5169a98e71c9e975596e31ab808e76d11f09"}, + {file = "lru_dict-1.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0e1845024c31e6ff246c9eb5e6f6f1a8bb564c06f8a7d6d031220044c081090b"}, + {file = "lru_dict-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3ca5474b1649555d014be1104e5558a92497509021a5ba5ea6e9b492303eb66b"}, + {file = "lru_dict-1.3.0-cp310-cp310-win32.whl", hash = "sha256:ebb03a9bd50c2ed86d4f72a54e0aae156d35a14075485b2127c4b01a3f4a63fa"}, + {file = "lru_dict-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:04cda617f4e4c27009005d0a8185ef02829b14b776d2791f5c994cc9d668bc24"}, + {file = "lru_dict-1.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:20c595764695d20bdc3ab9b582e0cc99814da183544afb83783a36d6741a0dac"}, + {file = "lru_dict-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d9b30a8f50c3fa72a494eca6be5810a1b5c89e4f0fda89374f0d1c5ad8d37d51"}, + {file = "lru_dict-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9710737584650a4251b9a566cbb1a86f83437adb209c9ba43a4e756d12faf0d7"}, + {file = "lru_dict-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b84c321ae34f2f40aae80e18b6fa08b31c90095792ab64bb99d2e385143effaa"}, + {file = "lru_dict-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eed24272b4121b7c22f234daed99899817d81d671b3ed030c876ac88bc9dc890"}, + {file = "lru_dict-1.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd13af06dab7c6ee92284fd02ed9a5613a07d5c1b41948dc8886e7207f86dfd"}, + {file = "lru_dict-1.3.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1efc59bfba6aac33684d87b9e02813b0e2445b2f1c444dae2a0b396ad0ed60c"}, + {file = "lru_dict-1.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cfaf75ac574447afcf8ad998789071af11d2bcf6f947643231f692948839bd98"}, + {file = "lru_dict-1.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c95f8751e2abd6f778da0399c8e0239321d560dbc58cb063827123137d213242"}, + {file = "lru_dict-1.3.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:abd0c284b26b5c4ee806ca4f33ab5e16b4bf4d5ec9e093e75a6f6287acdde78e"}, + {file = "lru_dict-1.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2a47740652b25900ac5ce52667b2eade28d8b5fdca0ccd3323459df710e8210a"}, + {file = "lru_dict-1.3.0-cp311-cp311-win32.whl", hash = "sha256:a690c23fc353681ed8042d9fe8f48f0fb79a57b9a45daea2f0be1eef8a1a4aa4"}, + {file = "lru_dict-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:efd3f4e0385d18f20f7ea6b08af2574c1bfaa5cb590102ef1bee781bdfba84bc"}, + {file = "lru_dict-1.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c279068f68af3b46a5d649855e1fb87f5705fe1f744a529d82b2885c0e1fc69d"}, + {file = "lru_dict-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:350e2233cfee9f326a0d7a08e309372d87186565e43a691b120006285a0ac549"}, + {file = "lru_dict-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4eafb188a84483b3231259bf19030859f070321b00326dcb8e8c6cbf7db4b12f"}, + {file = "lru_dict-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73593791047e36b37fdc0b67b76aeed439fcea80959c7d46201240f9ec3b2563"}, + {file = "lru_dict-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1958cb70b9542773d6241974646e5410e41ef32e5c9e437d44040d59bd80daf2"}, + {file = "lru_dict-1.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc1cd3ed2cee78a47f11f3b70be053903bda197a873fd146e25c60c8e5a32cd6"}, + {file = "lru_dict-1.3.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82eb230d48eaebd6977a92ddaa6d788f14cf4f4bcf5bbffa4ddfd60d051aa9d4"}, + {file = "lru_dict-1.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5ad659cbc349d0c9ba8e536b5f40f96a70c360f43323c29f4257f340d891531c"}, + {file = "lru_dict-1.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ba490b8972531d153ac0d4e421f60d793d71a2f4adbe2f7740b3c55dce0a12f1"}, + {file = "lru_dict-1.3.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:c0131351b8a7226c69f1eba5814cbc9d1d8daaf0fdec1ae3f30508e3de5262d4"}, + {file = "lru_dict-1.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0e88dba16695f17f41701269fa046197a3fd7b34a8dba744c8749303ddaa18df"}, + {file = "lru_dict-1.3.0-cp312-cp312-win32.whl", hash = "sha256:6ffaf595e625b388babc8e7d79b40f26c7485f61f16efe76764e32dce9ea17fc"}, + {file = "lru_dict-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf9da32ef2582434842ab6ba6e67290debfae72771255a8e8ab16f3e006de0aa"}, + {file = "lru_dict-1.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c265f16c936a8ff3bb4b8a4bda0be94c15ec28b63e99fdb1439c1ffe4cd437db"}, + {file = "lru_dict-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:784ca9d3b0730b3ec199c0a58f66264c63dd5d438119c739c349a6a9be8e5f6e"}, + {file = "lru_dict-1.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e13b2f58f647178470adaa14603bb64cc02eeed32601772ccea30e198252883c"}, + {file = "lru_dict-1.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ffbce5c2e80f57937679553c8f27e61ec327c962bf7ea0b15f1d74277fd5363"}, + {file = "lru_dict-1.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7969cb034b3ccc707aff877c73c225c32d7e2a7981baa8f92f5dd4d468fe8c33"}, + {file = "lru_dict-1.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca9ab676609cce85dd65d91c275e47da676d13d77faa72de286fbea30fbaa596"}, + {file = "lru_dict-1.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f27c078b5d75989952acbf9b77e14c3dadc468a4aafe85174d548afbc5efc38b"}, + {file = "lru_dict-1.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6123aefe97762ad74215d05320a7f389f196f0594c8813534284d4eafeca1a96"}, + {file = "lru_dict-1.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cd869cadba9a63e1e7fe2dced4a5747d735135b86016b0a63e8c9e324ab629ac"}, + {file = "lru_dict-1.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:40a8daddc29c7edb09dfe44292cf111f1e93a8344349778721d430d336b50505"}, + {file = "lru_dict-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a03170e4152836987a88dcebde61aaeb73ab7099a00bb86509d45b3fe424230"}, + {file = "lru_dict-1.3.0-cp38-cp38-win32.whl", hash = "sha256:3b4f121afe10f5a82b8e317626eb1e1c325b3f104af56c9756064cd833b1950b"}, + {file = "lru_dict-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:1470f5828c7410e16c24b5150eb649647986e78924816e6fb0264049dea14a2b"}, + {file = "lru_dict-1.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a3c9f746a9917e784fffcedeac4c8c47a3dbd90cbe13b69e9140182ad97ce4b7"}, + {file = "lru_dict-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2789296819525a1f3204072dfcf3df6db8bcf69a8fc740ffd3de43a684ea7002"}, + {file = "lru_dict-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:170b66d29945391460351588a7bd8210a95407ae82efe0b855e945398a1d24ea"}, + {file = "lru_dict-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774ca88501a9effe8797c3db5a6685cf20978c9cb0fe836b6813cfe1ca60d8c9"}, + {file = "lru_dict-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:df2e119c6ae412d2fd641a55f8a1e2e51f45a3de3449c18b1b86c319ab79e0c4"}, + {file = "lru_dict-1.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28aa1ea42a7e48174bf513dc2416fea7511a547961e678dc6f5670ca987c18cb"}, + {file = "lru_dict-1.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9537e1cee6fa582cb68f2fb9ce82d51faf2ccc0a638b275d033fdcb1478eb80b"}, + {file = "lru_dict-1.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:64545fca797fe2c68c5168efb5f976c6e1459e058cab02445207a079180a3557"}, + {file = "lru_dict-1.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a193a14c66cfc0c259d05dddc5e566a4b09e8f1765e941503d065008feebea9d"}, + {file = "lru_dict-1.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:3cb1de0ce4137b060abaafed8474cc0ebd12cedd88aaa7f7b3ebb1ddfba86ae0"}, + {file = "lru_dict-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8551ccab1349d4bebedab333dfc8693c74ff728f4b565fe15a6bf7d296bd7ea9"}, + {file = "lru_dict-1.3.0-cp39-cp39-win32.whl", hash = "sha256:6cb0be5e79c3f34d69b90d8559f0221e374b974b809a22377122c4b1a610ff67"}, + {file = "lru_dict-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9f725f2a0bdf1c18735372d5807af4ea3b77888208590394d4660e3d07971f21"}, + {file = "lru_dict-1.3.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f8f7824db5a64581180ab9d09842e6dd9fcdc46aac9cb592a0807cd37ea55680"}, + {file = "lru_dict-1.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acd04b7e7b0c0c192d738df9c317093335e7282c64c9d1bb6b7ebb54674b4e24"}, + {file = "lru_dict-1.3.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5c20f236f27551e3f0adbf1a987673fb1e9c38d6d284502cd38f5a3845ef681"}, + {file = "lru_dict-1.3.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca3703ff03b03a1848c563bc2663d0ad813c1cd42c4d9cf75b623716d4415d9a"}, + {file = "lru_dict-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a9fb71ba262c6058a0017ce83d343370d0a0dbe2ae62c2eef38241ec13219330"}, + {file = "lru_dict-1.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f5b88a7c39e307739a3701194993455968fcffe437d1facab93546b1b8a334c1"}, + {file = "lru_dict-1.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2682bfca24656fb7a643621520d57b7fe684ed5fa7be008704c1235d38e16a32"}, + {file = "lru_dict-1.3.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96fc87ddf569181827458ec5ad8fa446c4690cffacda66667de780f9fcefd44d"}, + {file = "lru_dict-1.3.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcec98e2c7da7631f0811730303abc4bdfe70d013f7a11e174a2ccd5612a7c59"}, + {file = "lru_dict-1.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6bba2863060caeaedd8386b0c8ee9a7ce4d57a7cb80ceeddf440b4eff2d013ba"}, + {file = "lru_dict-1.3.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c497fb60279f1e1d7dfbe150b1b069eaa43f7e172dab03f206282f4994676c5"}, + {file = "lru_dict-1.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d9509d817a47597988615c1a322580c10100acad10c98dfcf3abb41e0e5877f"}, + {file = "lru_dict-1.3.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0213ab4e3d9a8d386c18e485ad7b14b615cb6f05df6ef44fb2a0746c6ea9278b"}, + {file = "lru_dict-1.3.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b50fbd69cd3287196796ab4d50e4cc741eb5b5a01f89d8e930df08da3010c385"}, + {file = "lru_dict-1.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5247d1f011f92666010942434020ddc5a60951fefd5d12a594f0e5d9f43e3b3b"}, ] [package.extras] @@ -1623,6 +1618,30 @@ pathspec = ">=0.9.0" [package.extras] dev = ["black (>=22.6.0)", "bump2version (>=1.0.0)", "coverage (>=6.0.0)", "flake8 (==5.0.4)", "mypy (>=0.900)", "mypy-extensions (==0.4.3)", "pylint (==2.14.5)", "pytest (>=6.0.0)", "pytest-cov (>=3.0.0)"] +[[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 = "matplotlib-inline" version = "0.1.6" @@ -1648,15 +1667,26 @@ files = [ {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] +[[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 = "more-itertools" -version = "10.1.0" +version = "10.2.0" description = "More routines for operating on iterables, beyond itertools" optional = false python-versions = ">=3.8" files = [ - {file = "more-itertools-10.1.0.tar.gz", hash = "sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a"}, - {file = "more_itertools-10.1.0-py3-none-any.whl", hash = "sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6"}, + {file = "more-itertools-10.2.0.tar.gz", hash = "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1"}, + {file = "more_itertools-10.2.0-py3-none-any.whl", hash = "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684"}, ] [[package]] @@ -1790,13 +1820,13 @@ testing = ["docopt", "pytest (<6.0.0)"] [[package]] name = "pathspec" -version = "0.11.2" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] @@ -1821,29 +1851,18 @@ testing = ["funcsigs", "pytest"] [[package]] name = "pexpect" -version = "4.8.0" +version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" files = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, ] [package.dependencies] ptyprocess = ">=0.5" -[[package]] -name = "pickleshare" -version = "0.7.5" -description = "Tiny 'shelve'-like database with concurrency support" -optional = false -python-versions = "*" -files = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] - [[package]] name = "pkginfo" version = "1.9.6" @@ -1875,13 +1894,13 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] @@ -1956,13 +1975,13 @@ poetry-core = ">=1.6.0,<2.0.0" [[package]] name = "pre-commit" -version = "3.5.0" +version = "3.6.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, - {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, + {file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"}, + {file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"}, ] [package.dependencies] @@ -1974,13 +1993,13 @@ virtualenv = ">=20.10.0" [[package]] name = "prompt-toolkit" -version = "3.0.39" +version = "3.0.43" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, - {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, + {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, + {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, ] [package.dependencies] @@ -2046,13 +2065,13 @@ test = ["pytest (==6.2.5)", "pytest-xdist (==1.26.0)"] [[package]] name = "py-evm" -version = "0.7.0a4" +version = "0.8.0b1" description = "Python implementation of the Ethereum Virtual Machine" optional = false python-versions = "*" files = [ - {file = "py-evm-0.7.0a4.tar.gz", hash = "sha256:d40b6ac950485111dc7ad7bd29e3f61e00d5f81dc919e8c2b3afca30f228dc05"}, - {file = "py_evm-0.7.0a4-py3-none-any.whl", hash = "sha256:1bf7b293faa70c03727358ae3e5cb0abf7282391461d9b52b82decd6ed18c2f7"}, + {file = "py-evm-0.8.0b1.tar.gz", hash = "sha256:a082eeef14d5189b7f98c76c2b3d75f2bdbe205447e57add27c1c392f5d55544"}, + {file = "py_evm-0.8.0b1-py3-none-any.whl", hash = "sha256:ae22ab813406c248f085caac6d689f3ce8f60ae60e861df6db1618e24c9e503e"}, ] [package.dependencies] @@ -2064,18 +2083,17 @@ eth-utils = ">=2.0.0,<3.0.0" lru-dict = ">=1.1.6" mypy-extensions = ">=1.0.0" py-ecc = ">=1.4.7,<7.0.0" -pyethash = ">=0.1.27,<1.0.0" rlp = ">=3,<4" trie = ">=2.0.0,<3" [package.extras] benchmark = ["termcolor (>=1.1.0,<2.0.0)", "web3 (>=4.1.0,<5.0.0)"] -dev = ["Sphinx (>=1.5.5,<2)", "black (>=23)", "bumpversion (>=0.5.3,<1)", "cached-property (>=1.5.1,<2)", "eth-bloom (>=1.0.3)", "eth-keys (>=0.4.0,<0.5.0)", "eth-typing (>=3.3.0,<4.0.0)", "eth-utils (>=2.0.0,<3.0.0)", "factory-boy (==2.11.1)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "hypothesis (>=5,<6)", "idna (==2.7)", "importlib-metadata (<5.0)", "isort (>=5.10.1)", "jinja2 (>=3.0.0,<3.1.0)", "lru-dict (>=1.1.6)", "mypy (==1.4.0)", "mypy-extensions (>=1.0.0)", "pexpect (>=4.6,<5)", "py-ecc (>=1.4.7,<7.0.0)", "py-evm (>=0.2.0-a.14)", "pydocstyle (>=6.0.0)", "pyethash (>=0.1.27,<1.0.0)", "pysha3 (>=1.0.0,<2.0.0)", "pytest (>=6.2.4,<7)", "pytest-asyncio (>=0.10.0,<0.11)", "pytest-cov (==2.5.1)", "pytest-timeout (>=1.4.2,<2)", "pytest-watch (>=4.1.0,<5)", "pytest-xdist (==2.3.0)", "requests (>=2.20,<3)", "rlp (>=3,<4)", "setuptools (>=36.2.0)", "sphinx-rtd-theme (>=0.1.9)", "sphinxcontrib-asyncio (>=0.2.0,<0.4)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "trie (>=2.0.0,<3)", "twine", "types-setuptools", "wheel"] -docs = ["Sphinx (>=1.5.5,<2)", "jinja2 (>=3.0.0,<3.1.0)", "py-evm (>=0.2.0-a.14)", "pysha3 (>=1.0.0,<2.0.0)", "sphinx-rtd-theme (>=0.1.9)", "sphinxcontrib-asyncio (>=0.2.0,<0.4)", "towncrier (>=21,<22)"] -eth = ["cached-property (>=1.5.1,<2)", "eth-bloom (>=1.0.3)", "eth-keys (>=0.4.0,<0.5.0)", "eth-typing (>=3.3.0,<4.0.0)", "eth-utils (>=2.0.0,<3.0.0)", "lru-dict (>=1.1.6)", "mypy-extensions (>=1.0.0)", "py-ecc (>=1.4.7,<7.0.0)", "pyethash (>=0.1.27,<1.0.0)", "rlp (>=3,<4)", "trie (>=2.0.0,<3)"] -eth-extra = ["blake2b-py (>=0.1.4,<0.2)", "coincurve (>=13.0.0,<14.0.0)", "eth-hash[pycryptodome]", "eth-hash[pysha3]", "plyvel (>=1.2.0,<2)"] +dev = ["Sphinx (>=1.5.5,<2)", "black (>=23)", "bumpversion (>=0.5.3,<1)", "cached-property (>=1.5.1,<2)", "eth-bloom (>=1.0.3)", "eth-keys (>=0.4.0,<0.5.0)", "eth-typing (>=3.3.0,<4.0.0)", "eth-utils (>=2.0.0,<3.0.0)", "factory-boy (==2.11.1)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "hypothesis (>=5,<6)", "idna (==2.7)", "importlib-metadata (<5.0)", "isort (>=5.10.1)", "jinja2 (>=3.0.0,<3.1.0)", "lru-dict (>=1.1.6)", "mypy (==1.4.0)", "mypy-extensions (>=1.0.0)", "pexpect (>=4.6,<5)", "py-ecc (>=1.4.7,<7.0.0)", "py-evm (>=0.2.0-a.14)", "pydocstyle (>=6.0.0)", "pytest (>=6.2.4,<7)", "pytest-asyncio (>=0.10.0,<0.11)", "pytest-cov (==2.5.1)", "pytest-timeout (>=2.0.0,<3)", "pytest-watch (>=4.1.0,<5)", "pytest-xdist (>=3.0)", "requests (>=2.20,<3)", "rlp (>=3,<4)", "setuptools (>=36.2.0)", "sphinx-rtd-theme (>=0.1.9)", "sphinxcontrib-asyncio (>=0.2.0,<0.4)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "trie (>=2.0.0,<3)", "twine", "types-setuptools", "wheel"] +docs = ["Sphinx (>=1.5.5,<2)", "jinja2 (>=3.0.0,<3.1.0)", "py-evm (>=0.2.0-a.14)", "sphinx-rtd-theme (>=0.1.9)", "sphinxcontrib-asyncio (>=0.2.0,<0.4)", "towncrier (>=21,<22)"] +eth = ["cached-property (>=1.5.1,<2)", "eth-bloom (>=1.0.3)", "eth-keys (>=0.4.0,<0.5.0)", "eth-typing (>=3.3.0,<4.0.0)", "eth-utils (>=2.0.0,<3.0.0)", "lru-dict (>=1.1.6)", "mypy-extensions (>=1.0.0)", "py-ecc (>=1.4.7,<7.0.0)", "rlp (>=3,<4)", "trie (>=2.0.0,<3)"] +eth-extra = ["blake2b-py (>=0.2.0,<0.3.0)", "coincurve (>=18.0.0)"] lint = ["black (>=23)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "importlib-metadata (<5.0)", "isort (>=5.10.1)", "mypy (==1.4.0)", "pydocstyle (>=6.0.0)", "types-setuptools"] -test = ["factory-boy (==2.11.1)", "hypothesis (>=5,<6)", "importlib-metadata (<5.0)", "pexpect (>=4.6,<5)", "pytest (>=6.2.4,<7)", "pytest-asyncio (>=0.10.0,<0.11)", "pytest-cov (==2.5.1)", "pytest-timeout (>=1.4.2,<2)", "pytest-watch (>=4.1.0,<5)", "pytest-xdist (==2.3.0)"] +test = ["factory-boy (==2.11.1)", "hypothesis (>=5,<6)", "importlib-metadata (<5.0)", "pexpect (>=4.6,<5)", "pytest (>=6.2.4,<7)", "pytest-asyncio (>=0.10.0,<0.11)", "pytest-cov (==2.5.1)", "pytest-timeout (>=2.0.0,<3)", "pytest-watch (>=4.1.0,<5)", "pytest-xdist (>=3.0)"] [[package]] name = "pycodestyle" @@ -2101,53 +2119,43 @@ files = [ [[package]] name = "pycryptodome" -version = "3.19.0" +version = "3.20.0" description = "Cryptographic library for Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "pycryptodome-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3006c44c4946583b6de24fe0632091c2653d6256b99a02a3db71ca06472ea1e4"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c760c8a0479a4042111a8dd2f067d3ae4573da286c53f13cf6f5c53a5c1f631"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:08ce3558af5106c632baf6d331d261f02367a6bc3733086ae43c0f988fe042db"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45430dfaf1f421cf462c0dd824984378bef32b22669f2635cb809357dbaab405"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a9bcd5f3794879e91970f2bbd7d899780541d3ff439d8f2112441769c9f2ccea"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:190c53f51e988dceb60472baddce3f289fa52b0ec38fbe5fd20dd1d0f795c551"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:22e0ae7c3a7f87dcdcf302db06ab76f20e83f09a6993c160b248d58274473bfa"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7822f36d683f9ad7bc2145b2c2045014afdbbd1d9922a6d4ce1cbd6add79a01e"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:05e33267394aad6db6595c0ce9d427fe21552f5425e116a925455e099fdf759a"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829b813b8ee00d9c8aba417621b94bc0b5efd18c928923802ad5ba4cf1ec709c"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:fc7a79590e2b5d08530175823a242de6790abc73638cc6dc9d2684e7be2f5e49"}, - {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:542f99d5026ac5f0ef391ba0602f3d11beef8e65aae135fa5b762f5ebd9d3bfb"}, - {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61bb3ccbf4bf32ad9af32da8badc24e888ae5231c617947e0f5401077f8b091f"}, - {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d49a6c715d8cceffedabb6adb7e0cbf41ae1a2ff4adaeec9432074a80627dea1"}, - {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e249a784cc98a29c77cea9df54284a44b40cafbfae57636dd2f8775b48af2434"}, - {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d033947e7fd3e2ba9a031cb2d267251620964705a013c5a461fa5233cc025270"}, - {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:84c3e4fffad0c4988aef0d5591be3cad4e10aa7db264c65fadbc633318d20bde"}, - {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:139ae2c6161b9dd5d829c9645d781509a810ef50ea8b657e2257c25ca20efe33"}, - {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5b1986c761258a5b4332a7f94a83f631c1ffca8747d75ab8395bf2e1b93283d9"}, - {file = "pycryptodome-3.19.0-cp35-abi3-win32.whl", hash = "sha256:536f676963662603f1f2e6ab01080c54d8cd20f34ec333dcb195306fa7826997"}, - {file = "pycryptodome-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:04dd31d3b33a6b22ac4d432b3274588917dcf850cc0c51c84eca1d8ed6933810"}, - {file = "pycryptodome-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:8999316e57abcbd8085c91bc0ef75292c8618f41ca6d2b6132250a863a77d1e7"}, - {file = "pycryptodome-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:a0ab84755f4539db086db9ba9e9f3868d2e3610a3948cbd2a55e332ad83b01b0"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0101f647d11a1aae5a8ce4f5fad6644ae1b22bb65d05accc7d322943c69a74a6"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1601e04d32087591d78e0b81e1e520e57a92796089864b20e5f18c9564b3fa"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:506c686a1eee6c00df70010be3b8e9e78f406af4f21b23162bbb6e9bdf5427bc"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7919ccd096584b911f2a303c593280869ce1af9bf5d36214511f5e5a1bed8c34"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:560591c0777f74a5da86718f70dfc8d781734cf559773b64072bbdda44b3fc3e"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cc2f2ae451a676def1a73c1ae9120cd31af25db3f381893d45f75e77be2400"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17940dcf274fcae4a54ec6117a9ecfe52907ed5e2e438fe712fe7ca502672ed5"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d04f5f623a280fbd0ab1c1d8ecbd753193ab7154f09b6161b0f857a1a676c15f"}, - {file = "pycryptodome-3.19.0.tar.gz", hash = "sha256:bc35d463222cdb4dbebd35e0784155c81e161b9284e567e7e933d722e533331e"}, -] - -[[package]] -name = "pyethash" -version = "0.1.27" -description = "Python wrappers for ethash, the ethereum proof of workhashing function" -optional = false -python-versions = "*" -files = [ - {file = "pyethash-0.1.27.tar.gz", hash = "sha256:ff66319ce26b9d77df1f610942634dac9742e216f2c27b051c0a2c2dec9c2818"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"}, + {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, ] [[package]] @@ -2163,17 +2171,18 @@ files = [ [[package]] name = "pygments" -version = "2.16.1" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" files = [ - {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, - {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] [package.extras] plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyproject-hooks" @@ -2211,13 +2220,13 @@ files = [ [[package]] name = "pytest" -version = "7.4.2" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, - {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -2262,13 +2271,13 @@ pytest = "*" [[package]] name = "pytest-xdist" -version = "3.3.1" +version = "3.5.0" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-xdist-3.3.1.tar.gz", hash = "sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93"}, - {file = "pytest_xdist-3.3.1-py3-none-any.whl", hash = "sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2"}, + {file = "pytest-xdist-3.5.0.tar.gz", hash = "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a"}, + {file = "pytest_xdist-3.5.0-py3-none-any.whl", hash = "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24"}, ] [package.dependencies] @@ -2352,119 +2361,101 @@ files = [ [[package]] name = "rapidfuzz" -version = "2.15.2" +version = "3.6.1" description = "rapid fuzzy string matching" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "rapidfuzz-2.15.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b2e64e08588965b2490ee6b581d3901dd207ec3f6919b1c8da495183acfde953"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0af367ecb515ae695d7da21b0bd05784f388621e9d6a2e21dc96e6ba5d18d95f"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:892d0d75f0b820d949b0bf9502f746cfcbaab98d8a47653fa8369607fde250f1"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcf1d564ec948a4bf0750252579871be1790de66200f4cf8d624446017d74ee9"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab2f86733fe34cd825b6cbc688d41b7eb19ae0ce1ea7dc57eac13862d4b9ecb5"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8bdc497a8930428fa35158c58a744ddaa930621b80adfb61884456d8f184288a"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97f6c4948ca07ad1a30e70da56ec672422ef6bf18d10b6a881e7a64ba73a126d"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f3e2cc54edffd62ae38a03802b79c0f0cec6c2f89819607350fb5c4c00442d7"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0a252ccb39d628d0f68bab80ba18a02e0d1853a0ec71991e665a6bf81a28c79a"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ff82edd7ff9796e2ca349aa583fcb6b9ae96db0b6c5a76dcf0c1f67b1cb86964"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0860877f455833e5ed7113e859a9b2bf9670b22fdc7a48b81384a04c4a8e8a48"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:1a78c75ad082fdd58fdcf04551b7737c96aa9e870f1b008b881fc179e7dc6208"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a9df54f67a22a2447b8b6648880de9ede5e2a2e568644e1de770df9bef5c2fb4"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-win32.whl", hash = "sha256:055e85bb1237142da4ed024f9986c3720d484036f8dd550b090582f288b71bb9"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:8f220df380c127ef8a9129d8878dabf99ed0f543597cf81dfdd30eca03843666"}, - {file = "rapidfuzz-2.15.2-cp310-cp310-win_arm64.whl", hash = "sha256:49972e202251ba60de41a7add8e86a055478020eabf3339300f46a8fdc35d048"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:29352510bcc2b7c3c7f3c1ab6f4c2115dc640cd79a9dc8e01adbae19fb96d359"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1ae3f741b9b3e95908158e6e56a5f11c1abc51754801dccd495e5cba734c541e"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a716bbded611cc82f7b27dcd7335b7bae49706c97a8738283464ff1536e7407"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ff36fb50f02259402d7cbdc96f75671b2cb14550db5ad6534a09a7f4940d796"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d60a2368e2564155d7209143a6b1dafa1eb457f31cf44698f917cba608d2341f"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c02fd6d75de19633f622daf6584cb6ed3148eac3a2b6b08fd3539c166de2921f"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5c875da0e0c9709dbdc6e33a7f061192e98943817e6d0e1f5d1d8b07050e349"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb74dcfadf0c5f520074455fe51fa0f62876e5473f5f60521d153afef888ef70"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5b31f65137e8e45c4fb2dda394bb31598cff8290fb0ce5e66c8cf47d1bc554cb"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:689008633f88cf8802dbd281ac745775aeeee67525d532fcbabda0c8bc5b2e32"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:02fd52352346c965fdc9de9d26f55d61941cc27c876a589eeb3f4efdb7dffdb1"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:454ab8b5c8fc526243133dab013f0a3355efcc1200829cfba7ef56280c7763fc"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fd40f263d1ad1cdd4b657e867654674315eea9abf3fce64269610b7bc81265ee"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-win32.whl", hash = "sha256:66db4817c54a6ca91234959c4f6d0cb1fd943ddfb379ee7f9e6dce99b522554e"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:3f8eaf74105ffea1d15198b109ff0ca7b6dccafc61e05fa5f98a53d925707c57"}, - {file = "rapidfuzz-2.15.2-cp311-cp311-win_arm64.whl", hash = "sha256:ed0ec102b5e405d7562e4df05729a89467ae5c8a364c52fcf8c129398e82e6c5"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c0c8475f029a50bf65571b59d332fccd3eb33c5e49283868490a973e9ca7c33c"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ee9ee24eb431d5f73d0b255dc8e66272967a58cd6670cca984a81bbfc7dde904"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a1ecd818c108cefea2c02a9a716e223f811e612a050c8625555336b65d1cabef"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3eda119ebcf501dc35054abd9a187b5249b3d93b3965485371efb48e735b72c"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7ba83d0846991f67c2ec12ff8530b5e0f929e32a57352080b5f95aade0a62e"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c279864902a9538b17547e0d9399f05f36ebb9f3356bc5bc4cec2ba137fa5a17"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c94e247011fa7eea14d210123ebda2ecdf98ccc114254353edb4501ee8a19d7"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675c9052b3a04a4b33c92f0b8952ef2439163853422cc583286351ee82fc4d26"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c2d64820ae7a795082208a2d762c6a291aca116b86e35c2831e468ae3d4bb5cd"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:c0f12cc4a8216edfaa0511aae34d8b2f824a05cfe5a26a08de9cf180ae584e88"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e27da009ef39dc64297bcdf09c8d4c79ac90d0015fcf0a01af2a802cd7e1803"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:ea541d56fbb7de717a013790c2bce655252da220f23db0c6ce24f628cbe228e6"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9f52338e4e69aff4260c84275c7a704d198315b9b84303e67e584971409347d0"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-win32.whl", hash = "sha256:d5550e0078b2618c4ea7ea761053337eb7c5f5cc515f4941d8108ce9b0c7ee8c"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:19f72cfe2553c83c5e383851aba2891dafbb6446b6ae1ec0637333558ddd564e"}, - {file = "rapidfuzz-2.15.2-cp312-cp312-win_arm64.whl", hash = "sha256:423ef2ca785da77cd081d5bbc57035dc9b91500008a1b8e8e811a0ba3871a5ee"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0a02f1b08879a74aa7b4e562823f67a2e913fe3bd18c5346d9270d16fc588500"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a100ca26804b9ac2b2c0f70c632102bc0005d2cafe6d748f5d01dbe569c378bf"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e9fb88659cff92eba1b441efe426a4c349372137ee713b3a3933cc6ead73234"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:58073d3ebed8c0f51e163654dcb5e34f1e8b67f7b23361441861c6021243184b"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f55ad06ff79c2ffa3d1f5b38ce8f3082fa4db57c04be7de85243bd0625ca4ef"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ceecb57ec9e5c0d5bd9bd2881731c59cdc9a2c51711fd0b29b5bf14bdcab465f"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6c32c855e16ef3890037569f6f1299857172c674cd8946244e5fb7d5cacb771a"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e46f82fda6f969da8be5a8f33a057b2a9c6e7b80ab8679344a72e6fb708a48fc"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:6edc9b138797c60c1276171d8c97f53b17e304ade37c022ff97b1e995f79ba79"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:b32e4fd756a32f92b6f8b707a682ab4054b90c835021c01d81baba22f6277172"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5fb89d3a8d389eca258aba913adc81a8b8231b48896abbcb2f05768455584c4e"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-win32.whl", hash = "sha256:03ceea6cc9e4442379aa8581fbe61bad6e12d7938b16fbdc8442c8d915ad1154"}, - {file = "rapidfuzz-2.15.2-cp37-cp37m-win_amd64.whl", hash = "sha256:cb9f24fafb5ed77fc2ce23b1d8351efcfdb4c05b5f3b96bf004e89344a3d30ed"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:aab133bea22acbd3fa3740989a2f21d0e275efede2bf406a25a84392086c32f9"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4e110224e0de4fe4876224104a79550d18df15459fe94adf24b4b644e31d69cc"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:780b006bd007e4a071a9c022733f56b0df1f8c269bb7e9dbe079a79e8d9d3b8d"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:898bee3fd785ee695d4cb0d3c689407809cafca472851904aa78143ca6634903"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34623f51ed5dcbb2ddb97b2fefda34e7b53a047c71aac5ec6b72e42d5263f8b2"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02b3612c9318006290e6e6d82f1f98b83aa4cf062075c5ea03fac71ba4d31499"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dd0aab9ffab0010ae28b60f64c98c09c93086b3dc0cb3da863e53a3ca14a2bd"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e772677a84a166531f975301cb91db234a56eb5b6785e79ff5cb335251580efc"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1b7a670aed23d9a8d27a0031fa059e8f50f3f7287bd5a075a448251029794de9"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:830f799e5ec534633dee3b26c6d5398461dd3ced22118ab590f7fd0f91263058"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e427a9c9c1a8adac7b0293ddfe8f5885edf4f425cfd8a3b7ceae20434ec0663c"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3a3df80a264a999a120e637f98a1460d4f2c815323dd605e2022eef97db55448"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1496540d2ce8b1b9f340e652b9306674fa657d8d3a0b9629421cf31ace219092"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-win32.whl", hash = "sha256:aabd9da406fec009c08d2cd1bfa444ee568edf8e7c9a9d5e609885fc81c243a3"}, - {file = "rapidfuzz-2.15.2-cp38-cp38-win_amd64.whl", hash = "sha256:d21c66b15fbe253d48399a9d9db361ab2b3462a59b78c9279d9d7d347f5ded91"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7ef4dea11b87234e8b08ee47df9d869ae071bdacb5e55df82673ab9fa622f1e0"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ee3d9bc953f232bffcbd973137505f6cf5be5ed9c2cdc5e4a5db4be33bf5a734"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:efb94f6adbbbdacac9f687eb151ae9220ee9f141bb259fe07e82a2087114c17e"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9c3e07d13661871aebc325b9b3acbd42355a1df1e21ad0435fc81980fd20607"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01bae563a010900abba857e485c3747a78d61c88431cc3d9bea894c7c3e521f"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a09187df670e344468597b2c6f5ddc7651be75c4b594baa62c9261a144e5c058"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fcbfe5497c93a1b8717ea38b41b47f7e9d155fbc36a6bbfa84b8c901875465af"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f997a93b85c5798fe139a46c68c85de06ff75b4fd52d52463e46573bff39774"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:199676b8a19746017a0fbad0eb11380cbda4f635b6d2ee477544743b7f99d947"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:499a170088049258d5118bff8cf88f88ef6054544edbea0f2920eba8669e5eb9"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:a69ebe7b493557c425ca1d64bf0b5599f0405772b5179070adc2f62f7867836f"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:00bd97cd31aad049400b70e0872b54457c4769b296176d5b064f6a5d6391909f"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cadabe1287314bc5053f57c6043df04e33cf5fba33514ca0f4c7b0b8476063a0"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-win32.whl", hash = "sha256:301709491a7960473c34501602cd85a7653df7e0d4189c0ded1e0fd86a83b6ca"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-win_amd64.whl", hash = "sha256:9c968a2330b6f2de93e6d54ef7ebd5e5724ee730cd6f225e977cebc7af1df366"}, - {file = "rapidfuzz-2.15.2-cp39-cp39-win_arm64.whl", hash = "sha256:c6776c27385f3fe5810f3c389f01957d5fa6c3c7f7a76fd9815f2933674f787f"}, - {file = "rapidfuzz-2.15.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0b4c632b684478fd8780970685a0c575a5bee65692727ff9898acf75d61cb3ff"}, - {file = "rapidfuzz-2.15.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b1cfca399461e1f534fbeb3c87f39f2c37ed71f8d1dfb02b78a5b3f81bf0ef"}, - {file = "rapidfuzz-2.15.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba35ec7256a86270a5e2d193ff0089cf84787a1aa94a48f5f6105f86feb8ca38"}, - {file = "rapidfuzz-2.15.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdfc137bbe2e942321f725004395444d2594077932ad55f927d6b6e884c09142"}, - {file = "rapidfuzz-2.15.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:153366a00ea22e79f051298fb9606bf9472bca5ce1b82319070fcbea2f7b97d7"}, - {file = "rapidfuzz-2.15.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6bf1c60432755ed8ab5870a932b7c9382435a240d727d3b5e68f9ff9f83a3556"}, - {file = "rapidfuzz-2.15.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a358eb275eadad0ac44f0fdb2255d6b373908c742f94e06b2190dbfaaaaa49b8"}, - {file = "rapidfuzz-2.15.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a34136ab5bbd1b9643f9072102a88471995100b5d734cfaa946d3b63e332e653"}, - {file = "rapidfuzz-2.15.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:796e53c5f78c159aff8e5003bca41bfe007c6a63ee7e7a289765a7db30429197"}, - {file = "rapidfuzz-2.15.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2ce4a91be05c28b57d5019b09cf0970305760623e34da95f2cddd9067e7fe91d"}, - {file = "rapidfuzz-2.15.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:237d5b4cbfacdef0a84f2ead0b4819c586bb74d05f4a380bd2f8489464b7b7fa"}, - {file = "rapidfuzz-2.15.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773dff970af0474d7d551a953a0075840ced30315d4885e038a289857ed33365"}, - {file = "rapidfuzz-2.15.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c536fbbebb496a76cac3a45f139bf023807b1fb6e2262e77f875fc9b6802ec4e"}, - {file = "rapidfuzz-2.15.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e85579a698c9436c2dac1583d4b07cca635faeb9a7adeab03d42938ec0fe9f58"}, - {file = "rapidfuzz-2.15.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:77c540546c0ea7cb229cd9823f9cd174c93988657727880bfdd6db7f353f93d6"}, - {file = "rapidfuzz-2.15.2.tar.gz", hash = "sha256:bfc1d38a7adcbe8912f980a5f46f27a801dd8655582ff0d4a2c0431c02b7ce33"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ac434fc71edda30d45db4a92ba5e7a42c7405e1a54cb4ec01d03cc668c6dcd40"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2a791168e119cfddf4b5a40470620c872812042f0621e6a293983a2d52372db0"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5a2f3e9df346145c2be94e4d9eeffb82fab0cbfee85bd4a06810e834fe7c03fa"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23de71e7f05518b0bbeef55d67b5dbce3bcd3e2c81e7e533051a2e9401354eb0"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d056e342989248d2bdd67f1955bb7c3b0ecfa239d8f67a8dfe6477b30872c607"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01835d02acd5d95c1071e1da1bb27fe213c84a013b899aba96380ca9962364bc"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed0f712e0bb5fea327e92aec8a937afd07ba8de4c529735d82e4c4124c10d5a0"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96cd19934f76a1264e8ecfed9d9f5291fde04ecb667faef5f33bdbfd95fe2d1f"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e06c4242a1354cf9d48ee01f6f4e6e19c511d50bb1e8d7d20bcadbb83a2aea90"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d73dcfe789d37c6c8b108bf1e203e027714a239e50ad55572ced3c004424ed3b"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:06e98ff000e2619e7cfe552d086815671ed09b6899408c2c1b5103658261f6f3"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:08b6fb47dd889c69fbc0b915d782aaed43e025df6979b6b7f92084ba55edd526"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a1788ebb5f5b655a15777e654ea433d198f593230277e74d51a2a1e29a986283"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-win32.whl", hash = "sha256:c65f92881753aa1098c77818e2b04a95048f30edbe9c3094dc3707d67df4598b"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:4243a9c35667a349788461aae6471efde8d8800175b7db5148a6ab929628047f"}, + {file = "rapidfuzz-3.6.1-cp310-cp310-win_arm64.whl", hash = "sha256:f59d19078cc332dbdf3b7b210852ba1f5db8c0a2cd8cc4c0ed84cc00c76e6802"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fbc07e2e4ac696497c5f66ec35c21ddab3fc7a406640bffed64c26ab2f7ce6d6"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40cced1a8852652813f30fb5d4b8f9b237112a0bbaeebb0f4cc3611502556764"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:82300e5f8945d601c2daaaac139d5524d7c1fdf719aa799a9439927739917460"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf97c321fd641fea2793abce0e48fa4f91f3c202092672f8b5b4e781960b891"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7420e801b00dee4a344ae2ee10e837d603461eb180e41d063699fb7efe08faf0"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:060bd7277dc794279fa95522af355034a29c90b42adcb7aa1da358fc839cdb11"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7e3375e4f2bfec77f907680328e4cd16cc64e137c84b1886d547ab340ba6928"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a490cd645ef9d8524090551016f05f052e416c8adb2d8b85d35c9baa9d0428ab"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2e03038bfa66d2d7cffa05d81c2f18fd6acbb25e7e3c068d52bb7469e07ff382"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b19795b26b979c845dba407fe79d66975d520947b74a8ab6cee1d22686f7967"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:064c1d66c40b3a0f488db1f319a6e75616b2e5fe5430a59f93a9a5e40a656d15"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3c772d04fb0ebeece3109d91f6122b1503023086a9591a0b63d6ee7326bd73d9"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:841eafba6913c4dfd53045835545ba01a41e9644e60920c65b89c8f7e60c00a9"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-win32.whl", hash = "sha256:266dd630f12696ea7119f31d8b8e4959ef45ee2cbedae54417d71ae6f47b9848"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:d79aec8aeee02ab55d0ddb33cea3ecd7b69813a48e423c966a26d7aab025cdfe"}, + {file = "rapidfuzz-3.6.1-cp311-cp311-win_arm64.whl", hash = "sha256:484759b5dbc5559e76fefaa9170147d1254468f555fd9649aea3bad46162a88b"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b2ef4c0fd3256e357b70591ffb9e8ed1d439fb1f481ba03016e751a55261d7c1"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:588c4b20fa2fae79d60a4e438cf7133d6773915df3cc0a7f1351da19eb90f720"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7142ee354e9c06e29a2636b9bbcb592bb00600a88f02aa5e70e4f230347b373e"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dfc557c0454ad22382373ec1b7df530b4bbd974335efe97a04caec936f2956a"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:03f73b381bdeccb331a12c3c60f1e41943931461cdb52987f2ecf46bfc22f50d"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b0ccc2ec1781c7e5370d96aef0573dd1f97335343e4982bdb3a44c133e27786"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da3e8c9f7e64bb17faefda085ff6862ecb3ad8b79b0f618a6cf4452028aa2222"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fde9b14302a31af7bdafbf5cfbb100201ba21519be2b9dedcf4f1048e4fbe65d"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1a23eee225dfb21c07f25c9fcf23eb055d0056b48e740fe241cbb4b22284379"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e49b9575d16c56c696bc7b06a06bf0c3d4ef01e89137b3ddd4e2ce709af9fe06"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:0a9fc714b8c290261669f22808913aad49553b686115ad0ee999d1cb3df0cd66"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:a3ee4f8f076aa92184e80308fc1a079ac356b99c39408fa422bbd00145be9854"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f056ba42fd2f32e06b2c2ba2443594873cfccc0c90c8b6327904fc2ddf6d5799"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-win32.whl", hash = "sha256:5d82b9651e3d34b23e4e8e201ecd3477c2baa17b638979deeabbb585bcb8ba74"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:dad55a514868dae4543ca48c4e1fc0fac704ead038dafedf8f1fc0cc263746c1"}, + {file = "rapidfuzz-3.6.1-cp312-cp312-win_arm64.whl", hash = "sha256:3c84294f4470fcabd7830795d754d808133329e0a81d62fcc2e65886164be83b"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e19d519386e9db4a5335a4b29f25b8183a1c3f78cecb4c9c3112e7f86470e37f"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01eb03cd880a294d1bf1a583fdd00b87169b9cc9c9f52587411506658c864d73"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:be368573255f8fbb0125a78330a1a40c65e9ba3c5ad129a426ff4289099bfb41"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3e5af946f419c30f5cb98b69d40997fe8580efe78fc83c2f0f25b60d0e56efb"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f382f7ffe384ce34345e1c0b2065451267d3453cadde78946fbd99a59f0cc23c"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be156f51f3a4f369e758505ed4ae64ea88900dcb2f89d5aabb5752676d3f3d7e"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1936d134b6c513fbe934aeb668b0fee1ffd4729a3c9d8d373f3e404fbb0ce8a0"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ff8eaf4a9399eb2bebd838f16e2d1ded0955230283b07376d68947bbc2d33d"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae598a172e3a95df3383634589660d6b170cc1336fe7578115c584a99e0ba64d"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cd4ba4c18b149da11e7f1b3584813159f189dc20833709de5f3df8b1342a9759"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:0402f1629e91a4b2e4aee68043a30191e5e1b7cd2aa8dacf50b1a1bcf6b7d3ab"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:1e12319c6b304cd4c32d5db00b7a1e36bdc66179c44c5707f6faa5a889a317c0"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0bbfae35ce4de4c574b386c43c78a0be176eeddfdae148cb2136f4605bebab89"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-win32.whl", hash = "sha256:7fec74c234d3097612ea80f2a80c60720eec34947066d33d34dc07a3092e8105"}, + {file = "rapidfuzz-3.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:a553cc1a80d97459d587529cc43a4c7c5ecf835f572b671107692fe9eddf3e24"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:757dfd7392ec6346bd004f8826afb3bf01d18a723c97cbe9958c733ab1a51791"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2963f4a3f763870a16ee076796be31a4a0958fbae133dbc43fc55c3968564cf5"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d2f0274595cc5b2b929c80d4e71b35041104b577e118cf789b3fe0a77b37a4c5"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f211e366e026de110a4246801d43a907cd1a10948082f47e8a4e6da76fef52"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a59472b43879012b90989603aa5a6937a869a72723b1bf2ff1a0d1edee2cc8e6"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a03863714fa6936f90caa7b4b50ea59ea32bb498cc91f74dc25485b3f8fccfe9"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd95b6b7bfb1584f806db89e1e0c8dbb9d25a30a4683880c195cc7f197eaf0c"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7183157edf0c982c0b8592686535c8b3e107f13904b36d85219c77be5cefd0d8"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ad9d74ef7c619b5b0577e909582a1928d93e07d271af18ba43e428dc3512c2a1"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b53137d81e770c82189e07a8f32722d9e4260f13a0aec9914029206ead38cac3"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:49b9ed2472394d306d5dc967a7de48b0aab599016aa4477127b20c2ed982dbf9"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:dec307b57ec2d5054d77d03ee4f654afcd2c18aee00c48014cb70bfed79597d6"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4381023fa1ff32fd5076f5d8321249a9aa62128eb3f21d7ee6a55373e672b261"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-win32.whl", hash = "sha256:8d7a072f10ee57c8413c8ab9593086d42aaff6ee65df4aa6663eecdb7c398dca"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:ebcfb5bfd0a733514352cfc94224faad8791e576a80ffe2fd40b2177bf0e7198"}, + {file = "rapidfuzz-3.6.1-cp39-cp39-win_arm64.whl", hash = "sha256:1c47d592e447738744905c18dda47ed155620204714e6df20eb1941bb1ba315e"}, + {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:eef8b346ab331bec12bbc83ac75641249e6167fab3d84d8f5ca37fd8e6c7a08c"}, + {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53251e256017e2b87f7000aee0353ba42392c442ae0bafd0f6b948593d3f68c6"}, + {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6dede83a6b903e3ebcd7e8137e7ff46907ce9316e9d7e7f917d7e7cdc570ee05"}, + {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e4da90e4c2b444d0a171d7444ea10152e07e95972bb40b834a13bdd6de1110c"}, + {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ca3dfcf74f2b6962f411c33dd95b0adf3901266e770da6281bc96bb5a8b20de9"}, + {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bcc957c0a8bde8007f1a8a413a632a1a409890f31f73fe764ef4eac55f59ca87"}, + {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:692c9a50bea7a8537442834f9bc6b7d29d8729a5b6379df17c31b6ab4df948c2"}, + {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c23ceaea27e790ddd35ef88b84cf9d721806ca366199a76fd47cfc0457a81b"}, + {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b155e67fff215c09f130555002e42f7517d0ea72cbd58050abb83cb7c880cec"}, + {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3028ee8ecc48250607fa8a0adce37b56275ec3b1acaccd84aee1f68487c8557b"}, + {file = "rapidfuzz-3.6.1.tar.gz", hash = "sha256:35660bee3ce1204872574fa041c7ad7ec5175b3053a4cb6e181463fc07013de7"}, ] [package.extras] @@ -2472,13 +2463,13 @@ full = ["numpy"] [[package]] name = "referencing" -version = "0.30.2" +version = "0.33.0" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.30.2-py3-none-any.whl", hash = "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf"}, - {file = "referencing-0.30.2.tar.gz", hash = "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0"}, + {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, + {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, ] [package.dependencies] @@ -2487,99 +2478,104 @@ rpds-py = ">=0.7.0" [[package]] name = "regex" -version = "2023.10.3" +version = "2023.12.25" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.7" files = [ - {file = "regex-2023.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4c34d4f73ea738223a094d8e0ffd6d2c1a1b4c175da34d6b0de3d8d69bee6bcc"}, - {file = "regex-2023.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8f4e49fc3ce020f65411432183e6775f24e02dff617281094ba6ab079ef0915"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cd1bccf99d3ef1ab6ba835308ad85be040e6a11b0977ef7ea8c8005f01a3c29"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81dce2ddc9f6e8f543d94b05d56e70d03a0774d32f6cca53e978dc01e4fc75b8"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c6b4d23c04831e3ab61717a707a5d763b300213db49ca680edf8bf13ab5d91b"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c15ad0aee158a15e17e0495e1e18741573d04eb6da06d8b84af726cfc1ed02ee"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6239d4e2e0b52c8bd38c51b760cd870069f0bdf99700a62cd509d7a031749a55"}, - {file = "regex-2023.10.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4a8bf76e3182797c6b1afa5b822d1d5802ff30284abe4599e1247be4fd6b03be"}, - {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9c727bbcf0065cbb20f39d2b4f932f8fa1631c3e01fcedc979bd4f51fe051c5"}, - {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3ccf2716add72f80714b9a63899b67fa711b654be3fcdd34fa391d2d274ce767"}, - {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:107ac60d1bfdc3edb53be75e2a52aff7481b92817cfdddd9b4519ccf0e54a6ff"}, - {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:00ba3c9818e33f1fa974693fb55d24cdc8ebafcb2e4207680669d8f8d7cca79a"}, - {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f0a47efb1dbef13af9c9a54a94a0b814902e547b7f21acb29434504d18f36e3a"}, - {file = "regex-2023.10.3-cp310-cp310-win32.whl", hash = "sha256:36362386b813fa6c9146da6149a001b7bd063dabc4d49522a1f7aa65b725c7ec"}, - {file = "regex-2023.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:c65a3b5330b54103e7d21cac3f6bf3900d46f6d50138d73343d9e5b2900b2353"}, - {file = "regex-2023.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90a79bce019c442604662d17bf69df99090e24cdc6ad95b18b6725c2988a490e"}, - {file = "regex-2023.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c7964c2183c3e6cce3f497e3a9f49d182e969f2dc3aeeadfa18945ff7bdd7051"}, - {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ef80829117a8061f974b2fda8ec799717242353bff55f8a29411794d635d964"}, - {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5addc9d0209a9afca5fc070f93b726bf7003bd63a427f65ef797a931782e7edc"}, - {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c148bec483cc4b421562b4bcedb8e28a3b84fcc8f0aa4418e10898f3c2c0eb9b"}, - {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d1f21af4c1539051049796a0f50aa342f9a27cde57318f2fc41ed50b0dbc4ac"}, - {file = "regex-2023.10.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b9ac09853b2a3e0d0082104036579809679e7715671cfbf89d83c1cb2a30f58"}, - {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ebedc192abbc7fd13c5ee800e83a6df252bec691eb2c4bedc9f8b2e2903f5e2a"}, - {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d8a993c0a0ffd5f2d3bda23d0cd75e7086736f8f8268de8a82fbc4bd0ac6791e"}, - {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:be6b7b8d42d3090b6c80793524fa66c57ad7ee3fe9722b258aec6d0672543fd0"}, - {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4023e2efc35a30e66e938de5aef42b520c20e7eda7bb5fb12c35e5d09a4c43f6"}, - {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0d47840dc05e0ba04fe2e26f15126de7c755496d5a8aae4a08bda4dd8d646c54"}, - {file = "regex-2023.10.3-cp311-cp311-win32.whl", hash = "sha256:9145f092b5d1977ec8c0ab46e7b3381b2fd069957b9862a43bd383e5c01d18c2"}, - {file = "regex-2023.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:b6104f9a46bd8743e4f738afef69b153c4b8b592d35ae46db07fc28ae3d5fb7c"}, - {file = "regex-2023.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff507ae210371d4b1fe316d03433ac099f184d570a1a611e541923f78f05037"}, - {file = "regex-2023.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be5e22bbb67924dea15039c3282fa4cc6cdfbe0cbbd1c0515f9223186fc2ec5f"}, - {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a992f702c9be9c72fa46f01ca6e18d131906a7180950958f766c2aa294d4b41"}, - {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7434a61b158be563c1362d9071358f8ab91b8d928728cd2882af060481244c9e"}, - {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2169b2dcabf4e608416f7f9468737583ce5f0a6e8677c4efbf795ce81109d7c"}, - {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9e908ef5889cda4de038892b9accc36d33d72fb3e12c747e2799a0e806ec841"}, - {file = "regex-2023.10.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12bd4bc2c632742c7ce20db48e0d99afdc05e03f0b4c1af90542e05b809a03d9"}, - {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bc72c231f5449d86d6c7d9cc7cd819b6eb30134bb770b8cfdc0765e48ef9c420"}, - {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bce8814b076f0ce5766dc87d5a056b0e9437b8e0cd351b9a6c4e1134a7dfbda9"}, - {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:ba7cd6dc4d585ea544c1412019921570ebd8a597fabf475acc4528210d7c4a6f"}, - {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b0c7d2f698e83f15228ba41c135501cfe7d5740181d5903e250e47f617eb4292"}, - {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5a8f91c64f390ecee09ff793319f30a0f32492e99f5dc1c72bc361f23ccd0a9a"}, - {file = "regex-2023.10.3-cp312-cp312-win32.whl", hash = "sha256:ad08a69728ff3c79866d729b095872afe1e0557251da4abb2c5faff15a91d19a"}, - {file = "regex-2023.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:39cdf8d141d6d44e8d5a12a8569d5a227f645c87df4f92179bd06e2e2705e76b"}, - {file = "regex-2023.10.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4a3ee019a9befe84fa3e917a2dd378807e423d013377a884c1970a3c2792d293"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76066d7ff61ba6bf3cb5efe2428fc82aac91802844c022d849a1f0f53820502d"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe50b61bab1b1ec260fa7cd91106fa9fece57e6beba05630afe27c71259c59b"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fd88f373cb71e6b59b7fa597e47e518282455c2734fd4306a05ca219a1991b0"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ab05a182c7937fb374f7e946f04fb23a0c0699c0450e9fb02ef567412d2fa3"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dac37cf08fcf2094159922edc7a2784cfcc5c70f8354469f79ed085f0328ebdf"}, - {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e54ddd0bb8fb626aa1f9ba7b36629564544954fff9669b15da3610c22b9a0991"}, - {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3367007ad1951fde612bf65b0dffc8fd681a4ab98ac86957d16491400d661302"}, - {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:16f8740eb6dbacc7113e3097b0a36065a02e37b47c936b551805d40340fb9971"}, - {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f4f2ca6df64cbdd27f27b34f35adb640b5d2d77264228554e68deda54456eb11"}, - {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:39807cbcbe406efca2a233884e169d056c35aa7e9f343d4e78665246a332f597"}, - {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7eece6fbd3eae4a92d7c748ae825cbc1ee41a89bb1c3db05b5578ed3cfcfd7cb"}, - {file = "regex-2023.10.3-cp37-cp37m-win32.whl", hash = "sha256:ce615c92d90df8373d9e13acddd154152645c0dc060871abf6bd43809673d20a"}, - {file = "regex-2023.10.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f649fa32fe734c4abdfd4edbb8381c74abf5f34bc0b3271ce687b23729299ed"}, - {file = "regex-2023.10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b98b7681a9437262947f41c7fac567c7e1f6eddd94b0483596d320092004533"}, - {file = "regex-2023.10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:91dc1d531f80c862441d7b66c4505cd6ea9d312f01fb2f4654f40c6fdf5cc37a"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82fcc1f1cc3ff1ab8a57ba619b149b907072e750815c5ba63e7aa2e1163384a4"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7979b834ec7a33aafae34a90aad9f914c41fd6eaa8474e66953f3f6f7cbd4368"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef71561f82a89af6cfcbee47f0fabfdb6e63788a9258e913955d89fdd96902ab"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd829712de97753367153ed84f2de752b86cd1f7a88b55a3a775eb52eafe8a94"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00e871d83a45eee2f8688d7e6849609c2ca2a04a6d48fba3dff4deef35d14f07"}, - {file = "regex-2023.10.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:706e7b739fdd17cb89e1fbf712d9dc21311fc2333f6d435eac2d4ee81985098c"}, - {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cc3f1c053b73f20c7ad88b0d1d23be7e7b3901229ce89f5000a8399746a6e039"}, - {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f85739e80d13644b981a88f529d79c5bdf646b460ba190bffcaf6d57b2a9863"}, - {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:741ba2f511cc9626b7561a440f87d658aabb3d6b744a86a3c025f866b4d19e7f"}, - {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e77c90ab5997e85901da85131fd36acd0ed2221368199b65f0d11bca44549711"}, - {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:979c24cbefaf2420c4e377ecd1f165ea08cc3d1fbb44bdc51bccbbf7c66a2cb4"}, - {file = "regex-2023.10.3-cp38-cp38-win32.whl", hash = "sha256:58837f9d221744d4c92d2cf7201c6acd19623b50c643b56992cbd2b745485d3d"}, - {file = "regex-2023.10.3-cp38-cp38-win_amd64.whl", hash = "sha256:c55853684fe08d4897c37dfc5faeff70607a5f1806c8be148f1695be4a63414b"}, - {file = "regex-2023.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2c54e23836650bdf2c18222c87f6f840d4943944146ca479858404fedeb9f9af"}, - {file = "regex-2023.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:69c0771ca5653c7d4b65203cbfc5e66db9375f1078689459fe196fe08b7b4930"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ac965a998e1388e6ff2e9781f499ad1eaa41e962a40d11c7823c9952c77123e"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c0e8fae5b27caa34177bdfa5a960c46ff2f78ee2d45c6db15ae3f64ecadde14"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c56c3d47da04f921b73ff9415fbaa939f684d47293f071aa9cbb13c94afc17d"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ef1e014eed78ab650bef9a6a9cbe50b052c0aebe553fb2881e0453717573f52"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d29338556a59423d9ff7b6eb0cb89ead2b0875e08fe522f3e068b955c3e7b59b"}, - {file = "regex-2023.10.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9c6d0ced3c06d0f183b73d3c5920727268d2201aa0fe6d55c60d68c792ff3588"}, - {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:994645a46c6a740ee8ce8df7911d4aee458d9b1bc5639bc968226763d07f00fa"}, - {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:66e2fe786ef28da2b28e222c89502b2af984858091675044d93cb50e6f46d7af"}, - {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:11175910f62b2b8c055f2b089e0fedd694fe2be3941b3e2633653bc51064c528"}, - {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:06e9abc0e4c9ab4779c74ad99c3fc10d3967d03114449acc2c2762ad4472b8ca"}, - {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fb02e4257376ae25c6dd95a5aec377f9b18c09be6ebdefa7ad209b9137b73d48"}, - {file = "regex-2023.10.3-cp39-cp39-win32.whl", hash = "sha256:3b2c3502603fab52d7619b882c25a6850b766ebd1b18de3df23b2f939360e1bd"}, - {file = "regex-2023.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:adbccd17dcaff65704c856bd29951c58a1bd4b2b0f8ad6b826dbd543fe740988"}, - {file = "regex-2023.10.3.tar.gz", hash = "sha256:3fef4f844d2290ee0ba57addcec17eec9e3df73f10a2748485dfd6a3a188cc0f"}, + {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5"}, + {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8"}, + {file = "regex-2023.12.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d865984b3f71f6d0af64d0d88f5733521698f6c16f445bb09ce746c92c97c586"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0eabac536b4cc7f57a5f3d095bfa557860ab912f25965e08fe1545e2ed8b4c"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c25a8ad70e716f96e13a637802813f65d8a6760ef48672aa3502f4c24ea8b400"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9b6d73353f777630626f403b0652055ebfe8ff142a44ec2cf18ae470395766e"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9cc99d6946d750eb75827cb53c4371b8b0fe89c733a94b1573c9dd16ea6c9e4"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88d1f7bef20c721359d8675f7d9f8e414ec5003d8f642fdfd8087777ff7f94b5"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cb3fe77aec8f1995611f966d0c656fdce398317f850d0e6e7aebdfe61f40e1cd"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7aa47c2e9ea33a4a2a05f40fcd3ea36d73853a2aae7b4feab6fc85f8bf2c9704"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:df26481f0c7a3f8739fecb3e81bc9da3fcfae34d6c094563b9d4670b047312e1"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c40281f7d70baf6e0db0c2f7472b31609f5bc2748fe7275ea65a0b4601d9b392"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d94a1db462d5690ebf6ae86d11c5e420042b9898af5dcf278bd97d6bda065423"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ba1b30765a55acf15dce3f364e4928b80858fa8f979ad41f862358939bdd1f2f"}, + {file = "regex-2023.12.25-cp310-cp310-win32.whl", hash = "sha256:150c39f5b964e4d7dba46a7962a088fbc91f06e606f023ce57bb347a3b2d4630"}, + {file = "regex-2023.12.25-cp310-cp310-win_amd64.whl", hash = "sha256:09da66917262d9481c719599116c7dc0c321ffcec4b1f510c4f8a066f8768105"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1b9d811f72210fa9306aeb88385b8f8bcef0dfbf3873410413c00aa94c56c2b6"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d902a43085a308cef32c0d3aea962524b725403fd9373dea18110904003bac97"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d166eafc19f4718df38887b2bbe1467a4f74a9830e8605089ea7a30dd4da8887"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7ad32824b7f02bb3c9f80306d405a1d9b7bb89362d68b3c5a9be53836caebdb"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:636ba0a77de609d6510235b7f0e77ec494d2657108f777e8765efc060094c98c"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fda75704357805eb953a3ee15a2b240694a9a514548cd49b3c5124b4e2ad01b"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f72cbae7f6b01591f90814250e636065850c5926751af02bb48da94dfced7baa"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db2a0b1857f18b11e3b0e54ddfefc96af46b0896fb678c85f63fb8c37518b3e7"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7502534e55c7c36c0978c91ba6f61703faf7ce733715ca48f499d3dbbd7657e0"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e8c7e08bb566de4faaf11984af13f6bcf6a08f327b13631d41d62592681d24fe"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:283fc8eed679758de38fe493b7d7d84a198b558942b03f017b1f94dda8efae80"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f44dd4d68697559d007462b0a3a1d9acd61d97072b71f6d1968daef26bc744bd"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:67d3ccfc590e5e7197750fcb3a2915b416a53e2de847a728cfa60141054123d4"}, + {file = "regex-2023.12.25-cp311-cp311-win32.whl", hash = "sha256:68191f80a9bad283432385961d9efe09d783bcd36ed35a60fb1ff3f1ec2efe87"}, + {file = "regex-2023.12.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d2af3f6b8419661a0c421584cfe8aaec1c0e435ce7e47ee2a97e344b98f794f"}, + {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8a0ccf52bb37d1a700375a6b395bff5dd15c50acb745f7db30415bae3c2b0715"}, + {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c3c4a78615b7762740531c27cf46e2f388d8d727d0c0c739e72048beb26c8a9d"}, + {file = "regex-2023.12.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ad83e7545b4ab69216cef4cc47e344d19622e28aabec61574b20257c65466d6a"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7a635871143661feccce3979e1727c4e094f2bdfd3ec4b90dfd4f16f571a87a"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d498eea3f581fbe1b34b59c697512a8baef88212f92e4c7830fcc1499f5b45a5"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43f7cd5754d02a56ae4ebb91b33461dc67be8e3e0153f593c509e21d219c5060"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51f4b32f793812714fd5307222a7f77e739b9bc566dc94a18126aba3b92b98a3"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba99d8077424501b9616b43a2d208095746fb1284fc5ba490139651f971d39d9"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4bfc2b16e3ba8850e0e262467275dd4d62f0d045e0e9eda2bc65078c0110a11f"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8c2c19dae8a3eb0ea45a8448356ed561be843b13cbc34b840922ddf565498c1c"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:60080bb3d8617d96f0fb7e19796384cc2467447ef1c491694850ebd3670bc457"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b77e27b79448e34c2c51c09836033056a0547aa360c45eeeb67803da7b0eedaf"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:518440c991f514331f4850a63560321f833979d145d7d81186dbe2f19e27ae3d"}, + {file = "regex-2023.12.25-cp312-cp312-win32.whl", hash = "sha256:e2610e9406d3b0073636a3a2e80db05a02f0c3169b5632022b4e81c0364bcda5"}, + {file = "regex-2023.12.25-cp312-cp312-win_amd64.whl", hash = "sha256:cc37b9aeebab425f11f27e5e9e6cf580be7206c6582a64467a14dda211abc232"}, + {file = "regex-2023.12.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:da695d75ac97cb1cd725adac136d25ca687da4536154cdc2815f576e4da11c69"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d126361607b33c4eb7b36debc173bf25d7805847346dd4d99b5499e1fef52bc7"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4719bb05094d7d8563a450cf8738d2e1061420f79cfcc1fa7f0a44744c4d8f73"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd58946bce44b53b06d94aa95560d0b243eb2fe64227cba50017a8d8b3cd3e2"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22a86d9fff2009302c440b9d799ef2fe322416d2d58fc124b926aa89365ec482"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2aae8101919e8aa05ecfe6322b278f41ce2994c4a430303c4cd163fef746e04f"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e692296c4cc2873967771345a876bcfc1c547e8dd695c6b89342488b0ea55cd8"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:263ef5cc10979837f243950637fffb06e8daed7f1ac1e39d5910fd29929e489a"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d6f7e255e5fa94642a0724e35406e6cb7001c09d476ab5fce002f652b36d0c39"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:88ad44e220e22b63b0f8f81f007e8abbb92874d8ced66f32571ef8beb0643b2b"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:3a17d3ede18f9cedcbe23d2daa8a2cd6f59fe2bf082c567e43083bba3fb00347"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d15b274f9e15b1a0b7a45d2ac86d1f634d983ca40d6b886721626c47a400bf39"}, + {file = "regex-2023.12.25-cp37-cp37m-win32.whl", hash = "sha256:ed19b3a05ae0c97dd8f75a5d8f21f7723a8c33bbc555da6bbe1f96c470139d3c"}, + {file = "regex-2023.12.25-cp37-cp37m-win_amd64.whl", hash = "sha256:a6d1047952c0b8104a1d371f88f4ab62e6275567d4458c1e26e9627ad489b445"}, + {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b43523d7bc2abd757119dbfb38af91b5735eea45537ec6ec3a5ec3f9562a1c53"}, + {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:efb2d82f33b2212898f1659fb1c2e9ac30493ac41e4d53123da374c3b5541e64"}, + {file = "regex-2023.12.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7fca9205b59c1a3d5031f7e64ed627a1074730a51c2a80e97653e3e9fa0d415"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086dd15e9435b393ae06f96ab69ab2d333f5d65cbe65ca5a3ef0ec9564dfe770"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e81469f7d01efed9b53740aedd26085f20d49da65f9c1f41e822a33992cb1590"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34e4af5b27232f68042aa40a91c3b9bb4da0eeb31b7632e0091afc4310afe6cb"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9852b76ab558e45b20bf1893b59af64a28bd3820b0c2efc80e0a70a4a3ea51c1"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff100b203092af77d1a5a7abe085b3506b7eaaf9abf65b73b7d6905b6cb76988"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cc038b2d8b1470364b1888a98fd22d616fba2b6309c5b5f181ad4483e0017861"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:094ba386bb5c01e54e14434d4caabf6583334090865b23ef58e0424a6286d3dc"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5cd05d0f57846d8ba4b71d9c00f6f37d6b97d5e5ef8b3c3840426a475c8f70f4"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:9aa1a67bbf0f957bbe096375887b2505f5d8ae16bf04488e8b0f334c36e31360"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:98a2636994f943b871786c9e82bfe7883ecdaba2ef5df54e1450fa9869d1f756"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37f8e93a81fc5e5bd8db7e10e62dc64261bcd88f8d7e6640aaebe9bc180d9ce2"}, + {file = "regex-2023.12.25-cp38-cp38-win32.whl", hash = "sha256:d78bd484930c1da2b9679290a41cdb25cc127d783768a0369d6b449e72f88beb"}, + {file = "regex-2023.12.25-cp38-cp38-win_amd64.whl", hash = "sha256:b521dcecebc5b978b447f0f69b5b7f3840eac454862270406a39837ffae4e697"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f7bc09bc9c29ebead055bcba136a67378f03d66bf359e87d0f7c759d6d4ffa31"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e14b73607d6231f3cc4622809c196b540a6a44e903bcfad940779c80dffa7be7"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9eda5f7a50141291beda3edd00abc2d4a5b16c29c92daf8d5bd76934150f3edc"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc6bb9aa69aacf0f6032c307da718f61a40cf970849e471254e0e91c56ffca95"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:298dc6354d414bc921581be85695d18912bea163a8b23cac9a2562bbcd5088b1"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f4e475a80ecbd15896a976aa0b386c5525d0ed34d5c600b6d3ebac0a67c7ddf"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531ac6cf22b53e0696f8e1d56ce2396311254eb806111ddd3922c9d937151dae"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22f3470f7524b6da61e2020672df2f3063676aff444db1daa283c2ea4ed259d6"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:89723d2112697feaa320c9d351e5f5e7b841e83f8b143dba8e2d2b5f04e10923"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0ecf44ddf9171cd7566ef1768047f6e66975788258b1c6c6ca78098b95cf9a3d"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:905466ad1702ed4acfd67a902af50b8db1feeb9781436372261808df7a2a7bca"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:4558410b7a5607a645e9804a3e9dd509af12fb72b9825b13791a37cd417d73a5"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7e316026cc1095f2a3e8cc012822c99f413b702eaa2ca5408a513609488cb62f"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3b1de218d5375cd6ac4b5493e0b9f3df2be331e86520f23382f216c137913d20"}, + {file = "regex-2023.12.25-cp39-cp39-win32.whl", hash = "sha256:11a963f8e25ab5c61348d090bf1b07f1953929c13bd2309a0662e9ff680763c9"}, + {file = "regex-2023.12.25-cp39-cp39-win_amd64.whl", hash = "sha256:e693e233ac92ba83a87024e1d32b5f9ab15ca55ddd916d878146f4e3406b5c91"}, + {file = "regex-2023.12.25.tar.gz", hash = "sha256:29171aa128da69afdf4bde412d5bedc335f2ca8fcfe4489038577d05f16181e5"}, ] [[package]] @@ -2619,21 +2615,21 @@ requests = ">=2.0.1,<3.0.0" [[package]] name = "rich" -version = "12.6.0" +version = "13.7.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false -python-versions = ">=3.6.3,<4.0.0" +python-versions = ">=3.7.0" files = [ - {file = "rich-12.6.0-py3-none-any.whl", hash = "sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e"}, - {file = "rich-12.6.0.tar.gz", hash = "sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0"}, + {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, + {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, ] [package.dependencies] -commonmark = ">=0.9.0,<0.10.0" -pygments = ">=2.6.0,<3.0.0" +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" [package.extras] -jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] +jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rlp" @@ -2658,110 +2654,110 @@ test = ["hypothesis (==5.19.0)", "pytest (>=6.2.5,<7)", "tox (>=2.9.1,<3)"] [[package]] name = "rpds-py" -version = "0.10.6" +version = "0.17.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.10.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:6bdc11f9623870d75692cc33c59804b5a18d7b8a4b79ef0b00b773a27397d1f6"}, - {file = "rpds_py-0.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:26857f0f44f0e791f4a266595a7a09d21f6b589580ee0585f330aaccccb836e3"}, - {file = "rpds_py-0.10.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7f5e15c953ace2e8dde9824bdab4bec50adb91a5663df08d7d994240ae6fa31"}, - {file = "rpds_py-0.10.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61fa268da6e2e1cd350739bb61011121fa550aa2545762e3dc02ea177ee4de35"}, - {file = "rpds_py-0.10.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c48f3fbc3e92c7dd6681a258d22f23adc2eb183c8cb1557d2fcc5a024e80b094"}, - {file = "rpds_py-0.10.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0503c5b681566e8b722fe8c4c47cce5c7a51f6935d5c7012c4aefe952a35eed"}, - {file = "rpds_py-0.10.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:734c41f9f57cc28658d98270d3436dba65bed0cfc730d115b290e970150c540d"}, - {file = "rpds_py-0.10.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a5d7ed104d158c0042a6a73799cf0eb576dfd5fc1ace9c47996e52320c37cb7c"}, - {file = "rpds_py-0.10.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e3df0bc35e746cce42579826b89579d13fd27c3d5319a6afca9893a9b784ff1b"}, - {file = "rpds_py-0.10.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:73e0a78a9b843b8c2128028864901f55190401ba38aae685350cf69b98d9f7c9"}, - {file = "rpds_py-0.10.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5ed505ec6305abd2c2c9586a7b04fbd4baf42d4d684a9c12ec6110deefe2a063"}, - {file = "rpds_py-0.10.6-cp310-none-win32.whl", hash = "sha256:d97dd44683802000277bbf142fd9f6b271746b4846d0acaf0cefa6b2eaf2a7ad"}, - {file = "rpds_py-0.10.6-cp310-none-win_amd64.whl", hash = "sha256:b455492cab07107bfe8711e20cd920cc96003e0da3c1f91297235b1603d2aca7"}, - {file = "rpds_py-0.10.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:e8cdd52744f680346ff8c1ecdad5f4d11117e1724d4f4e1874f3a67598821069"}, - {file = "rpds_py-0.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66414dafe4326bca200e165c2e789976cab2587ec71beb80f59f4796b786a238"}, - {file = "rpds_py-0.10.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc435d059f926fdc5b05822b1be4ff2a3a040f3ae0a7bbbe672babb468944722"}, - {file = "rpds_py-0.10.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8e7f2219cb72474571974d29a191714d822e58be1eb171f229732bc6fdedf0ac"}, - {file = "rpds_py-0.10.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3953c6926a63f8ea5514644b7afb42659b505ece4183fdaaa8f61d978754349e"}, - {file = "rpds_py-0.10.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2bb2e4826be25e72013916eecd3d30f66fd076110de09f0e750163b416500721"}, - {file = "rpds_py-0.10.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bf347b495b197992efc81a7408e9a83b931b2f056728529956a4d0858608b80"}, - {file = "rpds_py-0.10.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:102eac53bb0bf0f9a275b438e6cf6904904908562a1463a6fc3323cf47d7a532"}, - {file = "rpds_py-0.10.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40f93086eef235623aa14dbddef1b9fb4b22b99454cb39a8d2e04c994fb9868c"}, - {file = "rpds_py-0.10.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e22260a4741a0e7a206e175232867b48a16e0401ef5bce3c67ca5b9705879066"}, - {file = "rpds_py-0.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f4e56860a5af16a0fcfa070a0a20c42fbb2012eed1eb5ceeddcc7f8079214281"}, - {file = "rpds_py-0.10.6-cp311-none-win32.whl", hash = "sha256:0774a46b38e70fdde0c6ded8d6d73115a7c39d7839a164cc833f170bbf539116"}, - {file = "rpds_py-0.10.6-cp311-none-win_amd64.whl", hash = "sha256:4a5ee600477b918ab345209eddafde9f91c0acd931f3776369585a1c55b04c57"}, - {file = "rpds_py-0.10.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:5ee97c683eaface61d38ec9a489e353d36444cdebb128a27fe486a291647aff6"}, - {file = "rpds_py-0.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0713631d6e2d6c316c2f7b9320a34f44abb644fc487b77161d1724d883662e31"}, - {file = "rpds_py-0.10.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5a53f5998b4bbff1cb2e967e66ab2addc67326a274567697379dd1e326bded7"}, - {file = "rpds_py-0.10.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a555ae3d2e61118a9d3e549737bb4a56ff0cec88a22bd1dfcad5b4e04759175"}, - {file = "rpds_py-0.10.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:945eb4b6bb8144909b203a88a35e0a03d22b57aefb06c9b26c6e16d72e5eb0f0"}, - {file = "rpds_py-0.10.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:52c215eb46307c25f9fd2771cac8135d14b11a92ae48d17968eda5aa9aaf5071"}, - {file = "rpds_py-0.10.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1b3cd23d905589cb205710b3988fc8f46d4a198cf12862887b09d7aaa6bf9b9"}, - {file = "rpds_py-0.10.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64ccc28683666672d7c166ed465c09cee36e306c156e787acef3c0c62f90da5a"}, - {file = "rpds_py-0.10.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:516a611a2de12fbea70c78271e558f725c660ce38e0006f75139ba337d56b1f6"}, - {file = "rpds_py-0.10.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9ff93d3aedef11f9c4540cf347f8bb135dd9323a2fc705633d83210d464c579d"}, - {file = "rpds_py-0.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d858532212f0650be12b6042ff4378dc2efbb7792a286bee4489eaa7ba010586"}, - {file = "rpds_py-0.10.6-cp312-none-win32.whl", hash = "sha256:3c4eff26eddac49d52697a98ea01b0246e44ca82ab09354e94aae8823e8bda02"}, - {file = "rpds_py-0.10.6-cp312-none-win_amd64.whl", hash = "sha256:150eec465dbc9cbca943c8e557a21afdcf9bab8aaabf386c44b794c2f94143d2"}, - {file = "rpds_py-0.10.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:cf693eb4a08eccc1a1b636e4392322582db2a47470d52e824b25eca7a3977b53"}, - {file = "rpds_py-0.10.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4134aa2342f9b2ab6c33d5c172e40f9ef802c61bb9ca30d21782f6e035ed0043"}, - {file = "rpds_py-0.10.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e782379c2028a3611285a795b89b99a52722946d19fc06f002f8b53e3ea26ea9"}, - {file = "rpds_py-0.10.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f6da6d842195fddc1cd34c3da8a40f6e99e4a113918faa5e60bf132f917c247"}, - {file = "rpds_py-0.10.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4a9fe992887ac68256c930a2011255bae0bf5ec837475bc6f7edd7c8dfa254e"}, - {file = "rpds_py-0.10.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b788276a3c114e9f51e257f2a6f544c32c02dab4aa7a5816b96444e3f9ffc336"}, - {file = "rpds_py-0.10.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:caa1afc70a02645809c744eefb7d6ee8fef7e2fad170ffdeacca267fd2674f13"}, - {file = "rpds_py-0.10.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bddd4f91eede9ca5275e70479ed3656e76c8cdaaa1b354e544cbcf94c6fc8ac4"}, - {file = "rpds_py-0.10.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:775049dfa63fb58293990fc59473e659fcafd953bba1d00fc5f0631a8fd61977"}, - {file = "rpds_py-0.10.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:c6c45a2d2b68c51fe3d9352733fe048291e483376c94f7723458cfd7b473136b"}, - {file = "rpds_py-0.10.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0699ab6b8c98df998c3eacf51a3b25864ca93dab157abe358af46dc95ecd9801"}, - {file = "rpds_py-0.10.6-cp38-none-win32.whl", hash = "sha256:ebdab79f42c5961682654b851f3f0fc68e6cc7cd8727c2ac4ffff955154123c1"}, - {file = "rpds_py-0.10.6-cp38-none-win_amd64.whl", hash = "sha256:24656dc36f866c33856baa3ab309da0b6a60f37d25d14be916bd3e79d9f3afcf"}, - {file = "rpds_py-0.10.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:0898173249141ee99ffcd45e3829abe7bcee47d941af7434ccbf97717df020e5"}, - {file = "rpds_py-0.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e9184fa6c52a74a5521e3e87badbf9692549c0fcced47443585876fcc47e469"}, - {file = "rpds_py-0.10.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5752b761902cd15073a527b51de76bbae63d938dc7c5c4ad1e7d8df10e765138"}, - {file = "rpds_py-0.10.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99a57006b4ec39dbfb3ed67e5b27192792ffb0553206a107e4aadb39c5004cd5"}, - {file = "rpds_py-0.10.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09586f51a215d17efdb3a5f090d7cbf1633b7f3708f60a044757a5d48a83b393"}, - {file = "rpds_py-0.10.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e225a6a14ecf44499aadea165299092ab0cba918bb9ccd9304eab1138844490b"}, - {file = "rpds_py-0.10.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2039f8d545f20c4e52713eea51a275e62153ee96c8035a32b2abb772b6fc9e5"}, - {file = "rpds_py-0.10.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:34ad87a831940521d462ac11f1774edf867c34172010f5390b2f06b85dcc6014"}, - {file = "rpds_py-0.10.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dcdc88b6b01015da066da3fb76545e8bb9a6880a5ebf89e0f0b2e3ca557b3ab7"}, - {file = "rpds_py-0.10.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:25860ed5c4e7f5e10c496ea78af46ae8d8468e0be745bd233bab9ca99bfd2647"}, - {file = "rpds_py-0.10.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7854a207ef77319ec457c1eb79c361b48807d252d94348305db4f4b62f40f7f3"}, - {file = "rpds_py-0.10.6-cp39-none-win32.whl", hash = "sha256:e6fcc026a3f27c1282c7ed24b7fcac82cdd70a0e84cc848c0841a3ab1e3dea2d"}, - {file = "rpds_py-0.10.6-cp39-none-win_amd64.whl", hash = "sha256:e98c4c07ee4c4b3acf787e91b27688409d918212dfd34c872201273fdd5a0e18"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:68fe9199184c18d997d2e4293b34327c0009a78599ce703e15cd9a0f47349bba"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3339eca941568ed52d9ad0f1b8eb9fe0958fa245381747cecf2e9a78a5539c42"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a360cfd0881d36c6dc271992ce1eda65dba5e9368575663de993eeb4523d895f"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:031f76fc87644a234883b51145e43985aa2d0c19b063e91d44379cd2786144f8"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f36a9d751f86455dc5278517e8b65580eeee37d61606183897f122c9e51cef3"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:052a832078943d2b2627aea0d19381f607fe331cc0eb5df01991268253af8417"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023574366002bf1bd751ebaf3e580aef4a468b3d3c216d2f3f7e16fdabd885ed"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:defa2c0c68734f4a82028c26bcc85e6b92cced99866af118cd6a89b734ad8e0d"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:879fb24304ead6b62dbe5034e7b644b71def53c70e19363f3c3be2705c17a3b4"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:53c43e10d398e365da2d4cc0bcaf0854b79b4c50ee9689652cdc72948e86f487"}, - {file = "rpds_py-0.10.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:3777cc9dea0e6c464e4b24760664bd8831738cc582c1d8aacf1c3f546bef3f65"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:40578a6469e5d1df71b006936ce95804edb5df47b520c69cf5af264d462f2cbb"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:cf71343646756a072b85f228d35b1d7407da1669a3de3cf47f8bbafe0c8183a4"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10f32b53f424fc75ff7b713b2edb286fdbfc94bf16317890260a81c2c00385dc"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81de24a1c51cfb32e1fbf018ab0bdbc79c04c035986526f76c33e3f9e0f3356c"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac17044876e64a8ea20ab132080ddc73b895b4abe9976e263b0e30ee5be7b9c2"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e8a78bd4879bff82daef48c14d5d4057f6856149094848c3ed0ecaf49f5aec2"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78ca33811e1d95cac8c2e49cb86c0fb71f4d8409d8cbea0cb495b6dbddb30a55"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c63c3ef43f0b3fb00571cff6c3967cc261c0ebd14a0a134a12e83bdb8f49f21f"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:7fde6d0e00b2fd0dbbb40c0eeec463ef147819f23725eda58105ba9ca48744f4"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:79edd779cfc46b2e15b0830eecd8b4b93f1a96649bcb502453df471a54ce7977"}, - {file = "rpds_py-0.10.6-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9164ec8010327ab9af931d7ccd12ab8d8b5dc2f4c6a16cbdd9d087861eaaefa1"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d29ddefeab1791e3c751e0189d5f4b3dbc0bbe033b06e9c333dca1f99e1d523e"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:30adb75ecd7c2a52f5e76af50644b3e0b5ba036321c390b8e7ec1bb2a16dd43c"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd609fafdcdde6e67a139898196698af37438b035b25ad63704fd9097d9a3482"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6eef672de005736a6efd565577101277db6057f65640a813de6c2707dc69f396"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cf4393c7b41abbf07c88eb83e8af5013606b1cdb7f6bc96b1b3536b53a574b8"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad857f42831e5b8d41a32437f88d86ead6c191455a3499c4b6d15e007936d4cf"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d7360573f1e046cb3b0dceeb8864025aa78d98be4bb69f067ec1c40a9e2d9df"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d08f63561c8a695afec4975fae445245386d645e3e446e6f260e81663bfd2e38"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:f0f17f2ce0f3529177a5fff5525204fad7b43dd437d017dd0317f2746773443d"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:442626328600bde1d09dc3bb00434f5374948838ce75c41a52152615689f9403"}, - {file = "rpds_py-0.10.6-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e9616f5bd2595f7f4a04b67039d890348ab826e943a9bfdbe4938d0eba606971"}, - {file = "rpds_py-0.10.6.tar.gz", hash = "sha256:4ce5a708d65a8dbf3748d2474b580d606b1b9f91b5c6ab2a316e0b0cf7a4ba50"}, + {file = "rpds_py-0.17.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4128980a14ed805e1b91a7ed551250282a8ddf8201a4e9f8f5b7e6225f54170d"}, + {file = "rpds_py-0.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ff1dcb8e8bc2261a088821b2595ef031c91d499a0c1b031c152d43fe0a6ecec8"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d65e6b4f1443048eb7e833c2accb4fa7ee67cc7d54f31b4f0555b474758bee55"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a71169d505af63bb4d20d23a8fbd4c6ce272e7bce6cc31f617152aa784436f29"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:436474f17733c7dca0fbf096d36ae65277e8645039df12a0fa52445ca494729d"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10162fe3f5f47c37ebf6d8ff5a2368508fe22007e3077bf25b9c7d803454d921"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:720215373a280f78a1814becb1312d4e4d1077b1202a56d2b0815e95ccb99ce9"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70fcc6c2906cfa5c6a552ba7ae2ce64b6c32f437d8f3f8eea49925b278a61453"}, + {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:91e5a8200e65aaac342a791272c564dffcf1281abd635d304d6c4e6b495f29dc"}, + {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:99f567dae93e10be2daaa896e07513dd4bf9c2ecf0576e0533ac36ba3b1d5394"}, + {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24e4900a6643f87058a27320f81336d527ccfe503984528edde4bb660c8c8d59"}, + {file = "rpds_py-0.17.1-cp310-none-win32.whl", hash = "sha256:0bfb09bf41fe7c51413f563373e5f537eaa653d7adc4830399d4e9bdc199959d"}, + {file = "rpds_py-0.17.1-cp310-none-win_amd64.whl", hash = "sha256:20de7b7179e2031a04042e85dc463a93a82bc177eeba5ddd13ff746325558aa6"}, + {file = "rpds_py-0.17.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:65dcf105c1943cba45d19207ef51b8bc46d232a381e94dd38719d52d3980015b"}, + {file = "rpds_py-0.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:071bc28c589b86bc6351a339114fb7a029f5cddbaca34103aa573eba7b482382"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae35e8e6801c5ab071b992cb2da958eee76340e6926ec693b5ff7d6381441745"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149c5cd24f729e3567b56e1795f74577aa3126c14c11e457bec1b1c90d212e38"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e796051f2070f47230c745d0a77a91088fbee2cc0502e9b796b9c6471983718c"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e820ee1004327609b28db8307acc27f5f2e9a0b185b2064c5f23e815f248f8"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1957a2ab607f9added64478a6982742eb29f109d89d065fa44e01691a20fc20a"}, + {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8587fd64c2a91c33cdc39d0cebdaf30e79491cc029a37fcd458ba863f8815383"}, + {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4dc889a9d8a34758d0fcc9ac86adb97bab3fb7f0c4d29794357eb147536483fd"}, + {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2953937f83820376b5979318840f3ee47477d94c17b940fe31d9458d79ae7eea"}, + {file = "rpds_py-0.17.1-cp311-none-win32.whl", hash = "sha256:1bfcad3109c1e5ba3cbe2f421614e70439f72897515a96c462ea657261b96518"}, + {file = "rpds_py-0.17.1-cp311-none-win_amd64.whl", hash = "sha256:99da0a4686ada4ed0f778120a0ea8d066de1a0a92ab0d13ae68492a437db78bf"}, + {file = "rpds_py-0.17.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1dc29db3900cb1bb40353772417800f29c3d078dbc8024fd64655a04ee3c4bdf"}, + {file = "rpds_py-0.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82ada4a8ed9e82e443fcef87e22a3eed3654dd3adf6e3b3a0deb70f03e86142a"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d36b2b59e8cc6e576f8f7b671e32f2ff43153f0ad6d0201250a7c07f25d570e"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3677fcca7fb728c86a78660c7fb1b07b69b281964673f486ae72860e13f512ad"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:516fb8c77805159e97a689e2f1c80655c7658f5af601c34ffdb916605598cda2"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df3b6f45ba4515632c5064e35ca7f31d51d13d1479673185ba8f9fefbbed58b9"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a967dd6afda7715d911c25a6ba1517975acd8d1092b2f326718725461a3d33f9"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dbbb95e6fc91ea3102505d111b327004d1c4ce98d56a4a02e82cd451f9f57140"}, + {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02866e060219514940342a1f84303a1ef7a1dad0ac311792fbbe19b521b489d2"}, + {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2528ff96d09f12e638695f3a2e0c609c7b84c6df7c5ae9bfeb9252b6fa686253"}, + {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd345a13ce06e94c753dab52f8e71e5252aec1e4f8022d24d56decd31e1b9b23"}, + {file = "rpds_py-0.17.1-cp312-none-win32.whl", hash = "sha256:2a792b2e1d3038daa83fa474d559acfd6dc1e3650ee93b2662ddc17dbff20ad1"}, + {file = "rpds_py-0.17.1-cp312-none-win_amd64.whl", hash = "sha256:292f7344a3301802e7c25c53792fae7d1593cb0e50964e7bcdcc5cf533d634e3"}, + {file = "rpds_py-0.17.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:8ffe53e1d8ef2520ebcf0c9fec15bb721da59e8ef283b6ff3079613b1e30513d"}, + {file = "rpds_py-0.17.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4341bd7579611cf50e7b20bb8c2e23512a3dc79de987a1f411cb458ab670eb90"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4eb548daf4836e3b2c662033bfbfc551db58d30fd8fe660314f86bf8510b93"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b686f25377f9c006acbac63f61614416a6317133ab7fafe5de5f7dc8a06d42eb"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e21b76075c01d65d0f0f34302b5a7457d95721d5e0667aea65e5bb3ab415c25"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b86b21b348f7e5485fae740d845c65a880f5d1eda1e063bc59bef92d1f7d0c55"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f175e95a197f6a4059b50757a3dca33b32b61691bdbd22c29e8a8d21d3914cae"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1701fc54460ae2e5efc1dd6350eafd7a760f516df8dbe51d4a1c79d69472fbd4"}, + {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9051e3d2af8f55b42061603e29e744724cb5f65b128a491446cc029b3e2ea896"}, + {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7450dbd659fed6dd41d1a7d47ed767e893ba402af8ae664c157c255ec6067fde"}, + {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5a024fa96d541fd7edaa0e9d904601c6445e95a729a2900c5aec6555fe921ed6"}, + {file = "rpds_py-0.17.1-cp38-none-win32.whl", hash = "sha256:da1ead63368c04a9bded7904757dfcae01eba0e0f9bc41d3d7f57ebf1c04015a"}, + {file = "rpds_py-0.17.1-cp38-none-win_amd64.whl", hash = "sha256:841320e1841bb53fada91c9725e766bb25009cfd4144e92298db296fb6c894fb"}, + {file = "rpds_py-0.17.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f6c43b6f97209e370124baf2bf40bb1e8edc25311a158867eb1c3a5d449ebc7a"}, + {file = "rpds_py-0.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7d63ec01fe7c76c2dbb7e972fece45acbb8836e72682bde138e7e039906e2c"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81038ff87a4e04c22e1d81f947c6ac46f122e0c80460b9006e6517c4d842a6ec"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:810685321f4a304b2b55577c915bece4c4a06dfe38f6e62d9cc1d6ca8ee86b99"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:25f071737dae674ca8937a73d0f43f5a52e92c2d178330b4c0bb6ab05586ffa6"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa5bfb13f1e89151ade0eb812f7b0d7a4d643406caaad65ce1cbabe0a66d695f"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfe07308b311a8293a0d5ef4e61411c5c20f682db6b5e73de6c7c8824272c256"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a000133a90eea274a6f28adc3084643263b1e7c1a5a66eb0a0a7a36aa757ed74"}, + {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d0e8a6434a3fbf77d11448c9c25b2f25244226cfbec1a5159947cac5b8c5fa4"}, + {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:efa767c220d94aa4ac3a6dd3aeb986e9f229eaf5bce92d8b1b3018d06bed3772"}, + {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:dbc56680ecf585a384fbd93cd42bc82668b77cb525343170a2d86dafaed2a84b"}, + {file = "rpds_py-0.17.1-cp39-none-win32.whl", hash = "sha256:270987bc22e7e5a962b1094953ae901395e8c1e1e83ad016c5cfcfff75a15a3f"}, + {file = "rpds_py-0.17.1-cp39-none-win_amd64.whl", hash = "sha256:2a7b2f2f56a16a6d62e55354dd329d929560442bd92e87397b7a9586a32e3e76"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a3264e3e858de4fc601741498215835ff324ff2482fd4e4af61b46512dd7fc83"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f2f3b28b40fddcb6c1f1f6c88c6f3769cd933fa493ceb79da45968a21dccc920"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9584f8f52010295a4a417221861df9bea4c72d9632562b6e59b3c7b87a1522b7"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c64602e8be701c6cfe42064b71c84ce62ce66ddc6422c15463fd8127db3d8066"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:060f412230d5f19fc8c8b75f315931b408d8ebf56aec33ef4168d1b9e54200b1"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9412abdf0ba70faa6e2ee6c0cc62a8defb772e78860cef419865917d86c7342"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9737bdaa0ad33d34c0efc718741abaafce62fadae72c8b251df9b0c823c63b22"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9f0e4dc0f17dcea4ab9d13ac5c666b6b5337042b4d8f27e01b70fae41dd65c57"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1db228102ab9d1ff4c64148c96320d0be7044fa28bd865a9ce628ce98da5973d"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8bbd8e56f3ba25a7d0cf980fc42b34028848a53a0e36c9918550e0280b9d0b6"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:be22ae34d68544df293152b7e50895ba70d2a833ad9566932d750d3625918b82"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bf046179d011e6114daf12a534d874958b039342b347348a78b7cdf0dd9d6041"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:1a746a6d49665058a5896000e8d9d2f1a6acba8a03b389c1e4c06e11e0b7f40d"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0b8bf5b8db49d8fd40f54772a1dcf262e8be0ad2ab0206b5a2ec109c176c0a4"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7f4cb1f173385e8a39c29510dd11a78bf44e360fb75610594973f5ea141028b"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7fbd70cb8b54fe745301921b0816c08b6d917593429dfc437fd024b5ba713c58"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bdf1303df671179eaf2cb41e8515a07fc78d9d00f111eadbe3e14262f59c3d0"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad059a4bd14c45776600d223ec194e77db6c20255578bb5bcdd7c18fd169361"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3664d126d3388a887db44c2e293f87d500c4184ec43d5d14d2d2babdb4c64cad"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:698ea95a60c8b16b58be9d854c9f993c639f5c214cf9ba782eca53a8789d6b19"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:c3d2010656999b63e628a3c694f23020322b4178c450dc478558a2b6ef3cb9bb"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:938eab7323a736533f015e6069a7d53ef2dcc841e4e533b782c2bfb9fb12d84b"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e626b365293a2142a62b9a614e1f8e331b28f3ca57b9f05ebbf4cf2a0f0bdc5"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:380e0df2e9d5d5d339803cfc6d183a5442ad7ab3c63c2a0982e8c824566c5ccc"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b760a56e080a826c2e5af09002c1a037382ed21d03134eb6294812dda268c811"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5576ee2f3a309d2bb403ec292d5958ce03953b0e57a11d224c1f134feaf8c40f"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3c3461ebb4c4f1bbc70b15d20b565759f97a5aaf13af811fcefc892e9197ba"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:637b802f3f069a64436d432117a7e58fab414b4e27a7e81049817ae94de45d8d"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffee088ea9b593cc6160518ba9bd319b5475e5f3e578e4552d63818773c6f56a"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ac732390d529d8469b831949c78085b034bff67f584559340008d0f6041a049"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:93432e747fb07fa567ad9cc7aaadd6e29710e515aabf939dfbed8046041346c6"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:7b7d9ca34542099b4e185b3c2a2b2eda2e318a7dbde0b0d83357a6d4421b5296"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:0387ce69ba06e43df54e43968090f3626e231e4bc9150e4c3246947567695f68"}, + {file = "rpds_py-0.17.1.tar.gz", hash = "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7"}, ] [[package]] @@ -2781,29 +2777,29 @@ jeepney = ">=0.6" [[package]] name = "setuptools" -version = "68.2.2" +version = "69.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, - {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, + {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, + {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +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)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "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.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "shellingham" -version = "1.5.3" +version = "1.5.4" description = "Tool to Detect Surrounding Shell" optional = false python-versions = ">=3.7" files = [ - {file = "shellingham-1.5.3-py2.py3-none-any.whl", hash = "sha256:419c6a164770c9c7cfcaeddfacb3d31ac7a8db0b0f3e9c1287679359734107e9"}, - {file = "shellingham-1.5.3.tar.gz", hash = "sha256:cb4a6fec583535bc6da17b647dd2330cf7ef30239e05d547d99ae3705fd0f7f8"}, + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, ] [[package]] @@ -2874,8 +2870,8 @@ forking-recommended = ["ujson"] [package.source] type = "git" url = "https://github.com/vyperlang/titanoboa.git" -reference = "03949fe9e3b1c15b8d88dd169b4f5e44fb64fae0" -resolved_reference = "03949fe9e3b1c15b8d88dd169b4f5e44fb64fae0" +reference = "8343f16bd35829421c0953373aa854fc52b41170" +resolved_reference = "8343f16bd35829421c0953373aa854fc52b41170" [[package]] name = "tomli" @@ -2890,96 +2886,95 @@ files = [ [[package]] name = "tomlkit" -version = "0.12.1" +version = "0.12.3" description = "Style preserving TOML library" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, - {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, + {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, + {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, ] [[package]] name = "toolz" -version = "0.12.0" +version = "0.12.1" description = "List processing tools and functional utilities" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" files = [ - {file = "toolz-0.12.0-py3-none-any.whl", hash = "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f"}, - {file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, + {file = "toolz-0.12.1-py3-none-any.whl", hash = "sha256:d22731364c07d72eea0a0ad45bafb2c2937ab6fd38a3507bf55eae8744aa7d85"}, + {file = "toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d"}, ] [[package]] name = "traitlets" -version = "5.11.2" +version = "5.14.1" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.11.2-py3-none-any.whl", hash = "sha256:98277f247f18b2c5cabaf4af369187754f4fb0e85911d473f72329db8a7f4fae"}, - {file = "traitlets-5.11.2.tar.gz", hash = "sha256:7564b5bf8d38c40fa45498072bf4dc5e8346eb087bbf1e2ae2d8774f6a0f078e"}, + {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, + {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.5.1)", "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,<7.5)", "pytest-mock", "pytest-mypy-testing"] [[package]] name = "trie" -version = "2.1.1" +version = "2.2.0" description = "Python implementation of the Ethereum Trie structure" optional = false -python-versions = ">=3.7,<4" +python-versions = ">=3.7, <4" files = [ - {file = "trie-2.1.1-py3-none-any.whl", hash = "sha256:c1a5fc17b37a75008a4517e4f297ad8026dce777eb0eed63ee6335c66d7437b7"}, - {file = "trie-2.1.1.tar.gz", hash = "sha256:1c7fa6f4a3088e083764cf4e32a07a69c672fcf15ad922e03f51158d64a855cf"}, + {file = "trie-2.2.0-py3-none-any.whl", hash = "sha256:b6ad00305722b271cd05c9475e741c92a61f0ca53e6cc4fa9a5591e37eac34ca"}, + {file = "trie-2.2.0.tar.gz", hash = "sha256:117a6f0844eb60f2f68ed45e621886690dacd16343394c1adfb3ff44231725bc"}, ] [package.dependencies] eth-hash = ">=0.1.0" eth-utils = ">=2.0.0" -hexbytes = ">=0.2.0" +hexbytes = ">=0.2.0,<0.4.0" rlp = ">=3" sortedcontainers = ">=2.1.0" [package.extras] -dev = ["black (>=23)", "build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash (>=0.1.0,<1.0.0)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "hypothesis (>=6.56.4,<7)", "isort (>=5.10.1)", "pycryptodome", "pytest (>=7.0.0)", "pytest-watch (>=4.1.0)", "pytest-xdist (>=2.4.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +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)"] -lint = ["black (>=23)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "isort (>=5.10.1)"] test = ["hypothesis (>=6.56.4,<7)", "pycryptodome", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "trove-classifiers" -version = "2023.9.19" +version = "2024.1.8" description = "Canonical source for classifiers on PyPI (pypi.org)." optional = false python-versions = "*" files = [ - {file = "trove-classifiers-2023.9.19.tar.gz", hash = "sha256:3e700af445c802f251ce2b741ee78d2e5dfa5ab8115b933b89ca631b414691c9"}, - {file = "trove_classifiers-2023.9.19-py3-none-any.whl", hash = "sha256:55460364fe248294386d4dfa5d16544ec930493ecc6bd1db07a0d50afb37018e"}, + {file = "trove-classifiers-2024.1.8.tar.gz", hash = "sha256:6e36caf430ff6485c4b57a4c6b364a13f6a898d16b9417c6c37467e59c14b05a"}, + {file = "trove_classifiers-2024.1.8-py3-none-any.whl", hash = "sha256:3c1ff4deb10149c7e39ede6e5bbc107def64362ef1ee7590ec98d71fb92f1b6a"}, ] [[package]] name = "typing-extensions" -version = "4.8.0" +version = "4.9.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, ] [[package]] name = "urllib3" -version = "1.26.17" +version = "1.26.18" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-1.26.17-py2.py3-none-any.whl", hash = "sha256:94a757d178c9be92ef5539b8840d48dc9cf1b2709c9d6b588232a055c524458b"}, - {file = "urllib3-1.26.17.tar.gz", hash = "sha256:24d6a242c28d29af46c3fae832c36db3bbebcc533dd1bb549172cd739c82df21"}, + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, ] [package.extras] @@ -2989,19 +2984,19 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" -version = "20.24.5" +version = "20.25.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, - {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<4" +platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] @@ -3034,13 +3029,13 @@ test = ["eth-stdlib (==0.2.6)", "eth-tester[py-evm] (>=0.9.0b1,<0.10)", "hypothe [[package]] name = "wcwidth" -version = "0.2.8" +version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.8-py2.py3-none-any.whl", hash = "sha256:77f719e01648ed600dfa5402c347481c0992263b81a027344f3e1ba25493a704"}, - {file = "wcwidth-0.2.8.tar.gz", hash = "sha256:8705c569999ffbb4f6a87c6d1b80f324bd6db952f5eb0b95bc07517f4c1813d4"}, + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] [[package]] @@ -3056,13 +3051,13 @@ files = [ [[package]] name = "wheel" -version = "0.41.2" +version = "0.42.0" description = "A built-package format for Python" optional = false python-versions = ">=3.7" files = [ - {file = "wheel-0.41.2-py3-none-any.whl", hash = "sha256:75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8"}, - {file = "wheel-0.41.2.tar.gz", hash = "sha256:0c5ac5ff2afb79ac23ab82bab027a0be7b5dbcf2e54dc50efe4bf507de1f7985"}, + {file = "wheel-0.42.0-py3-none-any.whl", hash = "sha256:177f9c9b0d45c47873b619f5b650346d632cdc35fb5e4d25058e09c9e581433d"}, + {file = "wheel-0.42.0.tar.gz", hash = "sha256:c45be39f7882c9d34243236f2d63cbd58039e360f85d0913425fbd7ceea617a8"}, ] [package.extras] @@ -3187,4 +3182,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "b11f60d84eea1a9d63bb0c5dafd5e0193d75b0a01843d27011084e447fed6e27" +content-hash = "d46c8db7b93a0d5ab622f7d07f347e7ff492bf0a9f209355ddffaf8fb2e50f6c" diff --git a/pyproject.toml b/pyproject.toml index 7c62505b..6214d430 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ packages = [] [tool.poetry.dependencies] python = "^3.10" poetry = "1.5.1" -titanoboa = {git = "https://github.com/vyperlang/titanoboa.git", rev = "03949fe9e3b1c15b8d88dd169b4f5e44fb64fae0"} +titanoboa = {git = "https://github.com/vyperlang/titanoboa.git", rev = "8343f16bd35829421c0953373aa854fc52b41170"} vyper = "0.3.10" pycryptodome = "^3.18.0" pre-commit = "^3.3.3" @@ -63,9 +63,8 @@ known_first_party = "poetry" [tool.pytest.ini_options] markers = [ - "only_for_pool_type: running tests only for specific pool types", - "only_for_token_types: running tests only if tokens of specific types are in pool", - "no_auto_generate: dont generate tests for this one", + "only_plain_tokens", "only_oracle_tokens", "only_rebasing_tokens", + "skip_plain_tokens", "skip_oracle_tokens", "skip_rebasing_tokens", ] filterwarnings = [ "ignore:PytestUnknownMarkWarning" diff --git a/scripts/deploy_infra.py b/scripts/deploy_infra.py index be0c694c..8026a51e 100644 --- a/scripts/deploy_infra.py +++ b/scripts/deploy_infra.py @@ -139,7 +139,6 @@ def set_evm_version(contract_file, network) -> boa.vyper.contract.VyperDeployer: - with open(contract_file, "r") as f: source = f.read() @@ -159,7 +158,6 @@ def set_evm_version(contract_file, network) -> boa.vyper.contract.VyperDeployer: def check_and_deploy(contract_obj, contract_designation, network, blueprint: bool = False, args=[]): - deployed_contract = deployments[network][contract_designation] if not deployed_contract: @@ -180,7 +178,6 @@ def check_and_deploy(contract_obj, contract_designation, network, blueprint: boo def deploy_infra(network, url, account, fork=False): - logger.log(f"Deploying on {network} ...") if fork: @@ -192,9 +189,7 @@ def deploy_infra(network, url, account, fork=False): boa.set_env(NetworkEnv(url)) boa.env.add_account(Account.from_key(os.environ[account])) for _network, data in deploy_utils.curve_dao_network_settings.items(): - if _network in network: - owner = data.dao_ownership_contract fee_receiver = data.fee_receiver_address @@ -252,13 +247,7 @@ def deploy_infra(network, url, account, fork=False): def main(): - - deploy_infra( - "ethereum:mainnet", - os.environ["RPC_ETHEREUM"], - "FIDDYDEPLOYER", - fork=False, - ) + deploy_infra("ethereum:mainnet", os.environ["RPC_ETHEREUM"], "FIDDYDEPLOYER", fork=False) if __name__ == "__main__": diff --git a/scripts/deploy_pool.py b/scripts/deploy_pool.py index 885d6946..3965f70c 100644 --- a/scripts/deploy_pool.py +++ b/scripts/deploy_pool.py @@ -15,63 +15,27 @@ deployments = { # Ethereum - "ethereum:sepolia": { - "factory": "0xfb37b8D939FFa77114005e61CFc2e543d6F49A81", - }, - "ethereum:mainnet": { - "factory": "0x6A8cbed756804B16E05E741eDaBd5cB544AE21bf", - }, + "ethereum:sepolia": {"factory": "0xfb37b8D939FFa77114005e61CFc2e543d6F49A81"}, + "ethereum:mainnet": {"factory": "0x6A8cbed756804B16E05E741eDaBd5cB544AE21bf"}, # Layer 2 - "arbitrum:mainnet": { - "factory": "0x9AF14D26075f142eb3F292D5065EB3faa646167b", - }, - "optimism:mainnet": { - "factory": "0x5eeE3091f747E60a045a2E715a4c71e600e31F6E", - }, - "base:mainnet": { - "factory": "0xd2002373543Ce3527023C75e7518C274A51ce712", - }, - "linea:mainnet": { - "factory": "0x5eeE3091f747E60a045a2E715a4c71e600e31F6E", - }, - "scroll:mainnet": { - "factory": "0x5eeE3091f747E60a045a2E715a4c71e600e31F6E", - }, - "zksync:mainnet": { - "factory": "", - }, - "pzkevm:mainnet": { - "factory": "0xd2002373543Ce3527023C75e7518C274A51ce712", - }, + "arbitrum:mainnet": {"factory": "0x9AF14D26075f142eb3F292D5065EB3faa646167b"}, + "optimism:mainnet": {"factory": "0x5eeE3091f747E60a045a2E715a4c71e600e31F6E"}, + "base:mainnet": {"factory": "0xd2002373543Ce3527023C75e7518C274A51ce712"}, + "linea:mainnet": {"factory": "0x5eeE3091f747E60a045a2E715a4c71e600e31F6E"}, + "scroll:mainnet": {"factory": "0x5eeE3091f747E60a045a2E715a4c71e600e31F6E"}, + "zksync:mainnet": {"factory": ""}, + "pzkevm:mainnet": {"factory": "0xd2002373543Ce3527023C75e7518C274A51ce712"}, "mantle:mainnet": {"factory": ""}, # Layer 1 - "gnosis:mainnet": { - "factory": "0xbC0797015fcFc47d9C1856639CaE50D0e69FbEE8", - }, - "polygon:mainnet": { - "factory": "0x1764ee18e8B3ccA4787249Ceb249356192594585", - }, - "avax:mainnet": { - "factory": "0x1764ee18e8B3ccA4787249Ceb249356192594585", - }, - "ftm:mainnet": { - "factory": "0xe61Fb97Ef6eBFBa12B36Ffd7be785c1F5A2DE66b", - }, - "bsc:mainnet": { - "factory": "0xd7E72f3615aa65b92A4DBdC211E296a35512988B", - }, - "celo:mainnet": { - "factory": "0x1764ee18e8B3ccA4787249Ceb249356192594585", - }, - "kava:mainnet": { - "factory": "0x1764ee18e8B3ccA4787249Ceb249356192594585", - }, - "aurora:mainnet": { - "factory": "0x5eeE3091f747E60a045a2E715a4c71e600e31F6E", - }, - "tron:mainnet": { - "factory": "", - }, + "gnosis:mainnet": {"factory": "0xbC0797015fcFc47d9C1856639CaE50D0e69FbEE8"}, + "polygon:mainnet": {"factory": "0x1764ee18e8B3ccA4787249Ceb249356192594585"}, + "avax:mainnet": {"factory": "0x1764ee18e8B3ccA4787249Ceb249356192594585"}, + "ftm:mainnet": {"factory": "0xe61Fb97Ef6eBFBa12B36Ffd7be785c1F5A2DE66b"}, + "bsc:mainnet": {"factory": "0xd7E72f3615aa65b92A4DBdC211E296a35512988B"}, + "celo:mainnet": {"factory": "0x1764ee18e8B3ccA4787249Ceb249356192594585"}, + "kava:mainnet": {"factory": "0x1764ee18e8B3ccA4787249Ceb249356192594585"}, + "aurora:mainnet": {"factory": "0x5eeE3091f747E60a045a2E715a4c71e600e31F6E"}, + "tron:mainnet": {"factory": ""}, } @@ -130,7 +94,6 @@ class PoolSettings: def deploy_pool(network, url, account, pool_type, fork): - logger.log(f"Deploying pool on {network} ...") if fork: @@ -158,7 +121,6 @@ def deploy_pool(network, url, account, pool_type, fork): def deploy_gauge(network, url, account, pool_addr, fork): - logger.log(f"Deploying gauge for pool {pool_addr} on {network} ...") if fork: @@ -181,7 +143,6 @@ def deploy_gauge(network, url, account, pool_addr, fork): def deploy_pool_and_gauge(network, url, account, pool_type, fork): - logger.log(f"Deploying pool on {network} ...") if fork: @@ -211,7 +172,6 @@ def deploy_pool_and_gauge(network, url, account, pool_type, fork): def main(): - fork = False deploy_pool_and_gauge("ethereum:mainnet", os.environ["RPC_ETHEREUM"], "FIDDYDEPLOYER", "plain", fork) deploy_pool_and_gauge("ethereum:mainnet", "http://localhost:9090/", "FIDDYDEPLOYER", "meta", fork) diff --git a/scripts/deploy_proxy_admin.py b/scripts/deploy_proxy_admin.py index ca607c85..fca78790 100644 --- a/scripts/deploy_proxy_admin.py +++ b/scripts/deploy_proxy_admin.py @@ -13,7 +13,6 @@ def deploy_proxy_admin(network, url, account, fork=False): - logger.log(f"Deploying ProxyAdmin for {network} ...") if fork: @@ -35,12 +34,7 @@ def deploy_proxy_admin(network, url, account, fork=False): def main(): - deploy_proxy_admin( - ":mainnet", - os.environ["RPC_"], - "", - fork=False, - ) + deploy_proxy_admin(":mainnet", os.environ["RPC_"], "", fork=False) if __name__ == "__main__": diff --git a/scripts/deployment_utils.py b/scripts/deployment_utils.py index b7af3632..84ff7a58 100644 --- a/scripts/deployment_utils.py +++ b/scripts/deployment_utils.py @@ -58,8 +58,7 @@ class CurveNetworkSettings: fee_receiver_address="0xf3A431008396df8A8b2DF492C913706BDB0874ef", ), "zksync:mainnet": CurveNetworkSettings( - dao_ownership_contract="", - fee_receiver_address="0x4920088D9a5e5De9c098FCA4960d0DA5f4caa4c1", + dao_ownership_contract="", fee_receiver_address="0x4920088D9a5e5De9c098FCA4960d0DA5f4caa4c1" ), "pzkevm:mainnet": CurveNetworkSettings( dao_ownership_contract="0x8b3EFBEfa6eD222077455d6f0DCdA3bF4f3F57A6", @@ -98,10 +97,7 @@ class CurveNetworkSettings: dao_ownership_contract="0x98B4029CaBEf7Fd525A36B0BF8555EC1d42ec0B6", fee_receiver_address="0x98B4029CaBEf7Fd525A36B0BF8555EC1d42ec0B6", ), - "tron:mainnet": CurveNetworkSettings( - dao_ownership_contract="", - fee_receiver_address="", - ), + "tron:mainnet": CurveNetworkSettings(dao_ownership_contract="", fee_receiver_address=""), "mantle:mainnet": CurveNetworkSettings( dao_ownership_contract="0xf3A431008396df8A8b2DF492C913706BDB0874ef", fee_receiver_address="0xf3A431008396df8A8b2DF492C913706BDB0874ef", diff --git a/scripts/set_up_base_pools.py b/scripts/set_up_base_pools.py index 06d127ed..bcb57086 100644 --- a/scripts/set_up_base_pools.py +++ b/scripts/set_up_base_pools.py @@ -75,20 +75,14 @@ class BasePoolSettings: BasePoolSettings( # 2pool pool="0x7f90122BF0700F9E7e1F688fe926940E8839F353", lp_token="0x7f90122BF0700F9E7e1F688fe926940E8839F353", - coins=[ - "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", - "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", - ], + coins=["0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"], asset_types=[0, 0], n_coins=2, ), BasePoolSettings( # fraxbp pool="0xC9B8a3FDECB9D5b218d02555a8Baf332E5B740d5", lp_token="0xC9B8a3FDECB9D5b218d02555a8Baf332E5B740d5", - coins=[ - "0x17FC002b466eEc40DaE837Fc4bE5c67993ddBd6F", - "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", - ], + coins=["0x17FC002b466eEc40DaE837Fc4bE5c67993ddBd6F", "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8"], asset_types=[0, 0], n_coins=2, ), @@ -108,10 +102,7 @@ class BasePoolSettings: BasePoolSettings( # fraxbp pool="0x29A3d66B30Bc4AD674A4FDAF27578B64f6afbFe7", lp_token="0x29A3d66B30Bc4AD674A4FDAF27578B64f6afbFe7", - coins=[ - "0x2E3D870790dC77A83DD1d18184Acc7439A53f475", - "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", - ], + coins=["0x2E3D870790dC77A83DD1d18184Acc7439A53f475", "0x7F5c764cBc14f9669B88837ca1490cCa17c31607"], asset_types=[0, 0], n_coins=2, ), @@ -127,13 +118,12 @@ class BasePoolSettings: ], asset_types=[0, 0, 0], n_coins=3, - ), + ) ], } def set_up_base_pools(network, url, account, fork: bool = False): - logger.log(f"Connecting to {network} ...") if fork: boa.env.fork(url) @@ -154,12 +144,7 @@ def set_up_base_pools(network, url, account, fork: bool = False): if base_pool_data: # check if network has base pools: for data in base_pool_data: if to_checksum_address(data.pool) not in onboarded_base_pools: - factory.add_base_pool( - data.pool, - data.lp_token, - data.asset_types, - data.n_coins, - ) + factory.add_base_pool(data.pool, data.lp_token, data.asset_types, data.n_coins) logger.log(f"Added {data.pool} to factory {factory_address} on {network}.") else: logger.log(f"{data.pool} is already configured as a base pool in factory {factory_address}.") @@ -170,33 +155,12 @@ def set_up_base_pools(network, url, account, fork: bool = False): def main(): - fork = False - set_up_base_pools( - "ethereum:mainnet", - os.environ["RPC_ETHEREUM"], - "FIDDYDEPLOYER", - fork=fork, - ) - set_up_base_pools( - "arbitrum:mainnet", - os.environ["RPC_ARBITRUM"], - "FIDDYDEPLOYER", - fork=fork, - ) - set_up_base_pools( - "optimism:mainnet", - os.environ["RPC_OPTIMISM"], - "FIDDYDEPLOYER", - fork=fork, - ) - set_up_base_pools( - "gnosis:mainnet", - os.environ["RPC_GNOSIS"], - "FIDDYDEPLOYER", - fork=fork, - ) + set_up_base_pools("ethereum:mainnet", os.environ["RPC_ETHEREUM"], "FIDDYDEPLOYER", fork=fork) + set_up_base_pools("arbitrum:mainnet", os.environ["RPC_ARBITRUM"], "FIDDYDEPLOYER", fork=fork) + set_up_base_pools("optimism:mainnet", os.environ["RPC_OPTIMISM"], "FIDDYDEPLOYER", fork=fork) + set_up_base_pools("gnosis:mainnet", os.environ["RPC_GNOSIS"], "FIDDYDEPLOYER", fork=fork) if __name__ == "__main__": diff --git a/scripts/vote_utils.py b/scripts/vote_utils.py index fd7defe7..b9043e9a 100644 --- a/scripts/vote_utils.py +++ b/scripts/vote_utils.py @@ -47,7 +47,6 @@ def prepare_evm_script(target: Dict, actions: List[Tuple]) -> str: evm_script = "0x00000001" for address, fn_name, *args in actions: - contract = ape.Contract(address) fn = getattr(contract, fn_name) calldata = fn.as_transaction(*args, sender=agent.address, gas_price=0).data diff --git a/tests/conftest.py b/tests/conftest.py index ec03b6fd..f33f5d0f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,230 +1,106 @@ -import itertools import os +from itertools import combinations_with_replacement +from random import Random import boa import pytest -from tests.utils import get_asset_types_in_pool +from tests.constants import DECIMAL_PAIRS, POOL_TYPES, TOKEN_TYPES pytest_plugins = [ "tests.fixtures.accounts", "tests.fixtures.constants", + "tests.fixtures.contracts", "tests.fixtures.factory", "tests.fixtures.mocks", "tests.fixtures.pools", "tests.fixtures.tokens", ] -pool_types = {"basic": 0, "meta": 1} -token_types = {"plain": 0, "oracle": 1, "rebasing": 2} -return_types = {"revert": 0, "False": 1, "None": 2} - - -def pytest_addoption(parser): - parser.addoption( - "--pool-size", - action="store", - default="2", - help="pool size to test against", - ) - parser.addoption( - "--pool-types", - action="store", - default="basic,meta", - help="pool type to test against", - ) - parser.addoption( - "--token-types", - action="store", - default="plain,oracle,rebasing", - help="comma-separated list of ERC20 token types to test against", - ) - parser.addoption( - "--decimals", - action="store", - default="18,18", - help="comma-separated list of ERC20 token precisions to test against", - ) - parser.addoption( - "--return-type", - action="store", - default="revert,False,None", - help="comma-separated list of ERC20 token return types to test against", - ) +@pytest.fixture(autouse=True) +def boa_setup(): + boa.env.enable_fast_mode() + yield + # force reset of the environment to prevent memory leaking between tests + boa.env._contracts.clear() + boa.env._code_registry.clear() + boa.reset_env() -def pytest_generate_tests(metafunc): - pool_size = int(metafunc.config.getoption("pool_size")) - - if "pool_size" in metafunc.fixturenames: - metafunc.parametrize( - "pool_size", - [pool_size], - indirect=True, - ids=[f"(PoolSize={pool_size})"], - ) +def pytest_generate_tests(metafunc): if "pool_type" in metafunc.fixturenames: - cli_options = metafunc.config.getoption("pool_types").split(",") + pool_type_items = sorted(POOL_TYPES.items()) metafunc.parametrize( - "pool_type", - [pool_types[pool_type] for pool_type in cli_options], - indirect=True, - ids=[f"(PoolType={pool_type})" for pool_type in cli_options], + "pool_type", [v for k, v in pool_type_items], ids=[f"(PoolType={k})" for k, v in pool_type_items] ) if "pool_token_types" in metafunc.fixturenames: - cli_options = metafunc.config.getoption("token_types").split(",") - if "eth" in cli_options: - cli_options.remove("eth") - cli_options = ["eth"] + cli_options - - combinations = list(itertools.combinations_with_replacement(cli_options, pool_size)) - + pool_token_pairs = get_pool_token_pairs(metafunc) metafunc.parametrize( "pool_token_types", - [[token_types[idx] for idx in c] for c in combinations], - indirect=True, - ids=[f"(PoolTokenTypes={c})" for c in combinations], + [(v1, v2) for (k1, v1), (k2, v2) in pool_token_pairs], + ids=[f"(PoolTokenTypes={k1}+{k2})" for (k1, v1), (k2, v2) in pool_token_pairs], ) if "metapool_token_type" in metafunc.fixturenames: - cli_options = metafunc.config.getoption("token_types").split(",") - # for meta pool only 1st coin is selected + token_type_items = get_tokens_for_metafunc(metafunc) metafunc.parametrize( "metapool_token_type", - [token_types[c] for c in cli_options], - indirect=True, - ids=[f"(MetaTokenType={c})" for c in cli_options], + [number for name, number in token_type_items], + ids=[f"(MetaTokenType={name})" for name, number in token_type_items], ) if "initial_decimals" in metafunc.fixturenames: - cli_options = metafunc.config.getoption("decimals") - metafunc.parametrize( - "initial_decimals", - [[int(i) for i in cli_options.split(",")]], - indirect=True, - ids=[f"(Decimals={cli_options})"], - ) + # this is only used in the decimals fixture + metafunc.parametrize("initial_decimals", DECIMAL_PAIRS, ids=[f"(Decimals={i},{j})" for i, j in DECIMAL_PAIRS]) - if "return_type" in metafunc.fixturenames: - cli_options = metafunc.config.getoption("return_type").split(",") - return_type_ids = [return_types[v] for v in cli_options] - - metafunc.parametrize( - "return_type", - return_type_ids, - indirect=True, - ids=[f"(ReturnType={i})" for i in cli_options], - ) +def get_pool_token_pairs(metafunc): + items = get_tokens_for_metafunc(metafunc) + # make all combinations possible + all_combinations = list(combinations_with_replacement(items, 2)) -@pytest.fixture(scope="session") -def pool_size(request): - return request.param - + if len(all_combinations) < 2: + return all_combinations -@pytest.fixture(scope="session") -def pool_type(request): - return request.param + # make sure we get the same result in each worker + random = Random(len(metafunc.fixturenames)) + # take 2 combinations for smaller test set + return sorted(random.sample(all_combinations, k=2)) -@pytest.fixture(scope="session") -def pool_token_types(request): - return request.param - - -@pytest.fixture(scope="session") -def metapool_token_type(request): - return request.param - +def get_tokens_for_metafunc(metafunc): + for name, number in TOKEN_TYPES.items(): + if metafunc.definition.get_closest_marker(f"only_{name}_tokens"): + return [(name, number)] -@pytest.fixture(scope="session") -def return_type(request): - return request.param + return [ + (name, number) + for name, number in TOKEN_TYPES.items() + if not metafunc.definition.get_closest_marker(f"skip_{name}_tokens") + ] @pytest.fixture(scope="session") -def initial_decimals(request): - return request.param +def pool_size(): + return 2 -@pytest.fixture(scope="session") +@pytest.fixture() def decimals(initial_decimals, pool_token_types): - # oracle tokens are always 18 decimals - return [d if t != 1 else 18 for d, t in zip(initial_decimals, pool_token_types)] + return [ + # oracle tokens are always 18 decimals + 18 if token_type == 1 else decimals + for decimals, token_type in zip(initial_decimals, pool_token_types) + ] -@pytest.fixture(scope="session") -def meta_decimals(initial_decimals, metapool_token_type, decimals): +@pytest.fixture() +def meta_decimals(metapool_token_type, decimals): # oracle tokens are always 18 decimals - return decimals[0] if metapool_token_type != 1 else 18 - - -# Usage -# @pytest.mark.only_for_token_types(1,2) -# -# will not be skipped only if at least one of tokens in pool is eth or oracle -# can be applied to classes -# -# @pytest.mark.only_for_token_types(2) -# class TestPoolsWithOracleToken: -@pytest.fixture(autouse=True) -def skip_by_token_type(request, pool_tokens): - only_for_token_types = request.node.get_closest_marker("only_for_token_types") - if only_for_token_types: - asset_types = [tkn.asset_type() for tkn in pool_tokens] - if not any(asset_type in only_for_token_types.args for asset_type in asset_types): - pytest.skip("skipped because no tokens for these types") - - -@pytest.fixture(autouse=True) -def skip_rebasing(request, swap): - only_for_token_types = request.node.get_closest_marker("skip_rebasing_tokens") - if only_for_token_types: - if 2 in get_asset_types_in_pool(swap): - pytest.skip("skipped because test includes rebasing tokens") - - -@pytest.fixture(autouse=True) -def skip_oracle(request, pool_tokens): - only_for_token_types = request.node.get_closest_marker("skip_oracle_tokens") - if only_for_token_types: - asset_types = [tkn.asset_type() for tkn in pool_tokens] - asset_types_contains_oracle = 1 in asset_types - if asset_types_contains_oracle: - pytest.skip("skipped because test includes oraclised tokens") - - -@pytest.fixture(autouse=True) -def only_oracle(request, pool_tokens): - only_for_token_types = request.node.get_closest_marker("only_oracle_tokens") - if only_for_token_types: - asset_types = [tkn.asset_type() for tkn in pool_tokens] - asset_types_contains_rebasing = 1 in asset_types - if not asset_types_contains_rebasing: - pytest.skip("skipped because test excludes oraclised tokens") - - -@pytest.fixture(autouse=True) -def only_rebasing(request, swap): - marker = request.node.get_closest_marker("contains_rebasing_tokens") - if marker: - asset_types_contains_rebasing = 2 in get_asset_types_in_pool(swap) - if not asset_types_contains_rebasing: - pytest.skip("skipped because test excludes rebasing tokens") - - -# Usage -# @pytest.mark.only_for_pool_type(1) -# class TestMetaPool... -@pytest.fixture(autouse=True) -def skip_by_pool_type(request, pool_type): - only_for_pool_type = request.node.get_closest_marker("only_for_pool_type") - if only_for_pool_type: - if pool_type not in only_for_pool_type.args: - pytest.skip("skipped because another pool type") + return 18 if metapool_token_type == 1 else decimals[0] @pytest.fixture(scope="module") diff --git a/tests/constants.py b/tests/constants.py new file mode 100644 index 00000000..073cdd09 --- /dev/null +++ b/tests/constants.py @@ -0,0 +1,3 @@ +POOL_TYPES = {"basic": 0, "meta": 1} +TOKEN_TYPES = {"plain": 0, "oracle": 1, "rebasing": 2} +DECIMAL_PAIRS = [(18, 18)] # TODO: Do we need more pairs? diff --git a/tests/factory/test_factory_add_pools.py b/tests/factory/test_factory_add_pools.py new file mode 100644 index 00000000..f4c92d01 --- /dev/null +++ b/tests/factory/test_factory_add_pools.py @@ -0,0 +1,107 @@ +import boa +import pytest + + +@pytest.fixture +def empty_factory(deployer, fee_receiver, owner): + with boa.env.prank(deployer): + _factory = boa.load("contracts/main/CurveStableSwapFactoryNG.vy", fee_receiver, owner) + return _factory + + +@pytest.fixture +def empty_factory_with_implementations( + empty_factory, + owner, + gauge_implementation, + views_implementation, + math_implementation, + amm_implementation, + amm_implementation_meta, +): + with boa.env.prank(owner): + empty_factory.set_gauge_implementation(gauge_implementation.address) + empty_factory.set_views_implementation(views_implementation.address) + empty_factory.set_math_implementation(math_implementation.address) + + empty_factory.set_pool_implementations(0, amm_implementation.address) + empty_factory.set_metapool_implementations(0, amm_implementation_meta.address) + + return empty_factory + + +def test_add_base_pool_already_exists(owner, factory, add_base_pool, base_pool, base_pool_lp_token, base_pool_tokens): + with boa.reverts(): + factory.add_base_pool( + base_pool.address, + base_pool_lp_token.address, + [0] * len(base_pool_tokens), + len(base_pool_tokens), + sender=owner, + ) + + +def test_add_base_pool_only_admin(factory, bob, base_pool, base_pool_lp_token, base_pool_tokens): + with boa.reverts(): + factory.add_base_pool( + base_pool.address, + base_pool_lp_token.address, + [0] * len(base_pool_tokens), + len(base_pool_tokens), + sender=bob, + ) + + +def test_deploy_plain_pool(empty_factory_with_implementations, amm_deployer, plain_tokens, pool_size, zero_address): + swap_address = empty_factory_with_implementations.deploy_plain_pool( + "test", + "test", + [t.address for t in (plain_tokens)], + 2000, + 1000000, + 20000000000, + 866, + 0, + [0] * pool_size, + [bytes(b"")] * pool_size, + [zero_address] * pool_size, + ) + assert swap_address != zero_address + + swap = amm_deployer.at(swap_address) + assert swap.coins(0) == plain_tokens[0].address + assert swap.coins(1) == plain_tokens[1].address + + assert swap.A() == 2000 + assert swap.fee() == 1000000 + + assert empty_factory_with_implementations.pool_count() == 1 + assert empty_factory_with_implementations.pool_list(0) == swap.address + assert empty_factory_with_implementations.get_decimals(swap) == [t.decimals() for t in (plain_tokens)] + + +def test_pool_count( + empty_factory_with_implementations, + add_base_pool, + amm_deployer, + set_pool_implementations, + pool_tokens, + pool_size, + zero_address, +): + assert empty_factory_with_implementations.pool_count() == 0 + + empty_factory_with_implementations.deploy_plain_pool( + "test", # name: String[32] + "test", # symbol: String[10] + [t.address for t in pool_tokens], # coins: address[] + 2000, # A: uint256 + 1000000, # fee: uint256 + 20000000000, # offpeg_fee_multiplier: uint256 + 866, # ma_exp_time: uint256 + 0, # implementation_idx: uint256 + [0] * pool_size, # asset_types: uint8[] + [bytes(b"")] * pool_size, # method_ids: bytes4[] + [zero_address] * pool_size, # oracles: address[] + ) + assert empty_factory_with_implementations.pool_count() == 1 diff --git a/tests/factory/test_factory_basic.py b/tests/factory/test_factory_basic.py new file mode 100644 index 00000000..c5a24049 --- /dev/null +++ b/tests/factory/test_factory_basic.py @@ -0,0 +1,60 @@ +import boa +import pytest + + +@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) +def test_find_pool_for_coins(factory, basic_swap, pool_tokens, sending, receiving): + assert ( + factory.find_pool_for_coins(pool_tokens[sending].address, pool_tokens[receiving].address) == basic_swap.address + ) + + +def test_get_n_coins(factory, basic_swap, pool_tokens, pool_size): + assert factory.get_n_coins(basic_swap.address) == 2 + + +def test_get_coins(factory, basic_swap, pool_tokens, pool_size): + assert factory.get_coins(basic_swap.address) == [pt.address for pt in pool_tokens] + + +def test_get_decimals(factory, basic_swap, decimals): + assert factory.get_decimals(basic_swap.address) == decimals + + +def test_get_balances(factory, basic_swap, pool_size): + assert factory.get_balances(basic_swap.address) == [basic_swap.balances(i) for i in range(pool_size)] + + +def test_get_underlying_balances(factory, basic_swap): + with boa.reverts() as e: + factory.get_underlying_balances(basic_swap.address) + assert str(e) == "dev: pool is not a metapool" + + +def test_get_A(factory, basic_swap): + assert factory.get_A(basic_swap.address) == basic_swap.A() + + +def test_get_fees(factory, basic_swap): + assert factory.get_fees(basic_swap.address) == (basic_swap.fee(), basic_swap.admin_fee()) + + +@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) +def test_get_coin_indices(factory, basic_swap, sending, receiving, pool_tokens): + i, j, is_underlying = factory.get_coin_indices( + basic_swap.address, pool_tokens[sending].address, pool_tokens[receiving].address + ) + assert i == sending + assert j == receiving + + +def test_get_implementation_address(factory, basic_swap, amm_implementation): + assert factory.get_implementation_address(basic_swap.address) == amm_implementation.address + + +def test_is_meta(factory, basic_swap): + assert factory.is_meta(basic_swap.address) is False + + +def test_get_pool_types(factory, basic_swap, pool_token_types): + assert factory.get_pool_asset_types(basic_swap.address) == list(pool_token_types) diff --git a/tests/test_factory_forked.py b/tests/factory/test_factory_forked.py similarity index 73% rename from tests/test_factory_forked.py rename to tests/factory/test_factory_forked.py index a624525d..6ba2e788 100644 --- a/tests/test_factory_forked.py +++ b/tests/factory/test_factory_forked.py @@ -5,15 +5,9 @@ @pytest.fixture def empty_factory(deployer, fee_receiver, owner): with boa.env.prank(deployer): - _factory = boa.load( - "contracts/main/CurveStableSwapFactoryNG.vy", - fee_receiver, - owner, - ) - return _factory + return boa.load("contracts/main/CurveStableSwapFactoryNG.vy", fee_receiver, owner) -@pytest.mark.only_for_pool_type(1) def test_add_base_pool(empty_factory, owner, forked_chain): fraxusdc = "0xdcef968d416a41cdac0ed8702fac8128a64241a2" lp_token = "0x3175df0976dfa876431c2e9ee6bc45b65d3473cc" diff --git a/tests/factory/test_factory_general.py b/tests/factory/test_factory_general.py new file mode 100644 index 00000000..d3d86c84 --- /dev/null +++ b/tests/factory/test_factory_general.py @@ -0,0 +1,15 @@ +def test_get_A(factory, swap, set_metapool_implementations): + assert factory.get_A(swap.address) == swap.A() + + +def test_get_fees(factory, swap): + assert factory.get_fees(swap.address) == (swap.fee(), swap.admin_fee()) + + +def test_get_admin_balances(factory, swap, pool_size): + balances = [swap.admin_balances(i) for i in range(pool_size)] + assert factory.get_admin_balances(swap.address) == balances + + +def test_fee_receiver(factory, fee_receiver): + assert factory.fee_receiver() == fee_receiver diff --git a/tests/factory/test_factory_meta.py b/tests/factory/test_factory_meta.py new file mode 100644 index 00000000..1243e964 --- /dev/null +++ b/tests/factory/test_factory_meta.py @@ -0,0 +1,68 @@ +import itertools + +import boa +import pytest + +MAX_COINS = 8 + + +@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) +def test_find_pool_for_coins(factory, meta_swap, underlying_tokens, sending, receiving): + assert ( + factory.find_pool_for_coins(underlying_tokens[sending].address, underlying_tokens[receiving].address) + == meta_swap.address + ) + + +@pytest.mark.parametrize("idx", range(1, 4)) +def test_find_pool_for_coins_underlying(factory, meta_swap, underlying_tokens, idx): + assert factory.find_pool_for_coins(underlying_tokens[0], underlying_tokens[idx]) == meta_swap.address + assert factory.find_pool_for_coins(underlying_tokens[idx], underlying_tokens[0]) == meta_swap.address + + +def test_get_meta_n_coins(factory, meta_swap): + assert factory.get_meta_n_coins(meta_swap.address) == (2, 4) + + +def test_get_underlying_coins(factory, meta_swap, underlying_tokens): + tokens = [underlying_tokens[0]] + underlying_tokens[2:] + assert factory.get_underlying_coins(meta_swap.address) == [t.address for t in tokens] + + +def test_get_underlying_decimals(factory, meta_swap, base_pool_decimals): + assert factory.get_underlying_decimals(meta_swap.address) == [18] + base_pool_decimals + + +def test_get_metapool_rates(meta_setup, factory, meta_swap, base_pool, base_pool_lp_token): + assert factory.get_metapool_rates(meta_swap.address) == [10**18, base_pool.get_virtual_price()] + + +def test_get_underlying_balances(meta_setup, factory, meta_swap, base_pool): + assert factory.get_metapool_rates(meta_swap.address) == [10**18, base_pool.get_virtual_price()] + + +@pytest.mark.parametrize("sending,receiving", itertools.permutations(range(1, 4), 2)) +def test_find_pool_underlying_base_pool_only(factory, underlying_tokens, sending, receiving, zero_address): + assert factory.find_pool_for_coins(underlying_tokens[sending], underlying_tokens[receiving]) == zero_address + + +@pytest.mark.parametrize("sending,receiving", itertools.permutations(range(2, 5), 2)) +def test_get_coin_indices_underlying(factory, meta_swap, sending, receiving, underlying_tokens): + i, j, is_underlying = factory.get_coin_indices(meta_swap, underlying_tokens[sending], underlying_tokens[receiving]) + assert i == sending - 1 + assert j == receiving - 1 + assert is_underlying is True + + +@pytest.mark.parametrize("idx", range(1, 4)) +def test_get_coin_indices_reverts(factory, meta_swap, base_pool_lp_token, underlying_tokens, idx): + with boa.reverts(): + factory.get_coin_indices(meta_swap.address, base_pool_lp_token.address, underlying_tokens[idx]) + + +def test_get_implementation_address(factory, meta_swap, amm_implementation_meta): + assert factory.get_implementation_address(meta_swap.address) == amm_implementation_meta.address + + +def test_is_meta(factory, meta_swap): + assert factory.is_meta(meta_swap.address) is True diff --git a/tests/fixtures/accounts.py b/tests/fixtures/accounts.py index 63e9f4c8..e4f2b2f4 100644 --- a/tests/fixtures/accounts.py +++ b/tests/fixtures/accounts.py @@ -6,69 +6,70 @@ from tests.utils.tokens import mint_for_testing +from ..constants import POOL_TYPES from .constants import INITIAL_AMOUNT -@pytest.fixture(scope="module") +@pytest.fixture() def deployer(): return boa.env.generate_address() -@pytest.fixture(scope="module") +@pytest.fixture() def owner(): return boa.env.generate_address() -@pytest.fixture(scope="module") +@pytest.fixture() def fee_receiver(): return boa.env.generate_address() -@pytest.fixture(scope="module") +@pytest.fixture() def eth_acc() -> LocalAccount: return Account.create() -@pytest.fixture(scope="module") +@pytest.fixture() def alice(): return boa.env.generate_address() -@pytest.fixture(scope="module") +@pytest.fixture() def bob(): return boa.env.generate_address() -@pytest.fixture(scope="module") +@pytest.fixture() def charlie(): return boa.env.generate_address() -@pytest.fixture(scope="module") +@pytest.fixture() def dave(): return boa.env.generate_address() -@pytest.fixture(scope="module") +@pytest.fixture() def erin(): return boa.env.generate_address() -@pytest.fixture(scope="module") +@pytest.fixture() def frank(): return boa.env.generate_address() -@pytest.fixture(scope="module") +@pytest.fixture() def accounts(bob, charlie, dave, erin, frank): return [bob, charlie, dave, erin, frank] # <--------------------- Functions ---------------------> def mint_account(account, pool_tokens, initial_balance, initial_amounts): - mint_for_testing(account, initial_balance, None, True) + mint_for_testing(account, initial_balance, token_contract=None, mint_eth=True) for pool_token, amount in zip(pool_tokens, initial_amounts): - mint_for_testing(account, amount, pool_token, False) + mint_for_testing(account, amount, pool_token, mint_eth=False) def approve_account(account, pool_tokens, swap): @@ -77,36 +78,6 @@ def approve_account(account, pool_tokens, swap): pool_token.approve(swap.address, 2**256 - 1) -@pytest.fixture(scope="module") -def mint_owner(owner, pool_tokens, initial_balance, initial_amounts): - mint_account(owner, pool_tokens, initial_balance, initial_amounts) - - -@pytest.fixture(scope="module") -def approve_owner(owner, pool_tokens, swap): - approve_account(owner, pool_tokens, swap) - - -@pytest.fixture(scope="module") -def mint_alice(alice, pool_tokens, initial_balance, initial_amounts): - mint_account(alice, pool_tokens, initial_balance, initial_amounts) - - -@pytest.fixture(scope="module") -def approve_alice(alice, pool_tokens, swap): - approve_account(alice, pool_tokens, swap) - - -@pytest.fixture(scope="module") -def mint_bob(bob, pool_tokens, initial_balance, initial_amounts): - mint_account(bob, pool_tokens, initial_balance, initial_amounts) - - -@pytest.fixture(scope="module") -def approve_bob(bob, pool_tokens, swap): - approve_account(bob, pool_tokens, swap) - - # <--------------------- Functions ---------------------> def add_base_pool_liquidity(user, base_pool, base_pool_tokens, base_pool_decimals): amount = INITIAL_AMOUNT // 3 @@ -119,135 +90,143 @@ def add_base_pool_liquidity(user, base_pool, base_pool_tokens, base_pool_decimal base_pool.add_liquidity(amounts, 0) -@pytest.fixture(scope="module") -def add_initial_liquidity_owner( +@pytest.fixture() +def add_initial_liquidity_owner_basic( owner, - approve_owner, - mint_owner, deposit_amounts, - swap, - pool_type, + basic_swap, underlying_tokens, base_pool, base_pool_tokens, base_pool_decimals, base_pool_lp_token, + pool_tokens, + initial_balance, + basic_initial_amounts, ): - if pool_type == 0: - with boa.env.prank(owner): - swap.add_liquidity(deposit_amounts, 0) - else: - add_base_pool_liquidity(owner, base_pool, base_pool_tokens, base_pool_decimals) - with boa.env.prank(owner): - base_pool_lp_token.approve(swap.address, 2**256 - 1) - lp_token_bal = base_pool_lp_token.balanceOf(owner) - to_mint_token0 = lp_token_bal * 10 ** underlying_tokens[0].decimals() // 10 ** base_pool_lp_token.decimals() + mint_account(owner, pool_tokens, initial_balance, basic_initial_amounts) + approve_account(owner, pool_tokens, basic_swap) + with boa.env.prank(owner): + basic_swap.add_liquidity(deposit_amounts, 0) - mint_for_testing(owner, to_mint_token0, underlying_tokens[0], False) - underlying_tokens[0].approve(swap.address, 2**256 - 1) - swap.add_liquidity([to_mint_token0, lp_token_bal], 0) - - -@pytest.fixture(scope="module") -def add_initial_liquidity_alice( - alice, - approve_alice, - mint_alice, - deposit_amounts, - swap, - pool_type, - base_pool, - base_pool_tokens, - base_pool_decimals, - base_pool_lp_token, -): - if pool_type == 0: - with boa.env.prank(alice): - swap.add_liquidity(deposit_amounts, 0) - else: - add_base_pool_liquidity(alice, base_pool, base_pool_tokens, base_pool_decimals) - with boa.env.prank(alice): - base_pool_lp_token.approve(swap.address, 2**256 - 1) - swap.add_liquidity(deposit_amounts, 0) - - -@pytest.fixture(scope="module") -def mint_meta_bob( - bob, - mint_bob, +@pytest.fixture() +def add_initial_liquidity_owner_meta( + owner, + deposit_meta_amounts, + meta_swap, + metapool_token, base_pool, base_pool_tokens, base_pool_decimals, - underlying_tokens, - initial_amounts, base_pool_lp_token, + pool_tokens, + initial_balance, + meta_initial_amounts, ): - add_base_pool_liquidity(bob, base_pool, base_pool_tokens, base_pool_decimals) - mint_for_testing(bob, initial_amounts[0], underlying_tokens[0], False) - assert underlying_tokens[0].balanceOf(bob) == base_pool_lp_token.balanceOf(bob) + mint_account(owner, pool_tokens, initial_balance, meta_initial_amounts) + approve_account(owner, pool_tokens, meta_swap) + add_base_pool_liquidity(owner, base_pool, base_pool_tokens, base_pool_decimals) + with boa.env.prank(owner): + base_pool_lp_token.approve(meta_swap.address, 2**256 - 1) + lp_token_bal = base_pool_lp_token.balanceOf(owner) + to_mint_token0 = lp_token_bal * 10 ** metapool_token.decimals() // 10 ** base_pool_lp_token.decimals() + + mint_for_testing(owner, to_mint_token0, metapool_token, False) + metapool_token.approve(meta_swap.address, 2**256 - 1) + + meta_swap.add_liquidity([to_mint_token0, lp_token_bal], 0) -@pytest.fixture(scope="module") +@pytest.fixture() +def add_initial_liquidity_owner(pool_type, request): + fixture_name = { + POOL_TYPES["basic"]: "add_initial_liquidity_owner_basic", + POOL_TYPES["meta"]: "add_initial_liquidity_owner_meta", + }[pool_type] + return request.getfixturevalue(fixture_name) + + +@pytest.fixture() def approve_meta_bob(bob, underlying_tokens, swap): with boa.env.prank(bob): for token in underlying_tokens: token.approve(swap.address, 2**256 - 1) -@pytest.fixture(scope="module") -def initial_setup( +@pytest.fixture() +def basic_setup( alice, bob, - approve_alice, - mint_alice, - deposit_amounts, - swap, - pool_type, + deposit_basic_amounts, + basic_swap, + initial_balance, + basic_initial_amounts, + pool_tokens, + metapool_token_type, +): + mint_account(alice, pool_tokens, initial_balance, basic_initial_amounts) + approve_account(alice, pool_tokens, basic_swap) + assert metapool_token_type is not None, "Fixture required downstream" + mint_for_testing(bob, 1 * 10**18, None, True) + + with boa.env.prank(alice): + basic_swap.add_liquidity(deposit_basic_amounts, 0) + + mint_account(bob, pool_tokens, initial_balance, basic_initial_amounts) + with boa.env.prank(bob): + for token in pool_tokens: + token.approve(basic_swap.address, 2**256 - 1) + + +@pytest.fixture() +def meta_setup( + alice, + bob, + deposit_meta_amounts, + meta_swap, base_pool, base_pool_tokens, base_pool_decimals, base_pool_lp_token, initial_balance, - initial_amounts, - pool_tokens, + meta_initial_amounts, underlying_tokens, + pool_tokens, + add_initial_liquidity_owner_meta, + metapool_token, ): - with boa.env.anchor(): - mint_for_testing(bob, 1 * 10**18, None, True) - - if pool_type == 0: - with boa.env.prank(alice): - swap.add_liquidity(deposit_amounts, 0) - - mint_account(bob, pool_tokens, initial_balance, initial_amounts) - with boa.env.prank(bob): - for token in pool_tokens: - token.approve(swap.address, 2**256 - 1) - - else: - add_base_pool_liquidity(alice, base_pool, base_pool_tokens, base_pool_decimals) - alice_bp_balance_norm = base_pool_lp_token.balanceOf(alice) / 10**18 - alice_mp_balance_norm = underlying_tokens[0].balanceOf(alice) / 10 ** underlying_tokens[0].decimals() - - if alice_mp_balance_norm < alice_bp_balance_norm: - mint_for_testing( - alice, - int(math.ceil(alice_bp_balance_norm) * 10 ** underlying_tokens[0].decimals()), - underlying_tokens[0], - ) - - with boa.env.prank(alice): - underlying_tokens[0].approve(swap.address, 2**256 - 1) - base_pool_lp_token.approve(swap.address, 2**256 - 1) - swap.add_liquidity(deposit_amounts, 0) - - add_base_pool_liquidity(bob, base_pool, base_pool_tokens, base_pool_decimals) - mint_for_testing(bob, initial_amounts[0], underlying_tokens[0], False) - assert underlying_tokens[0].balanceOf(bob) == pytest.approx(base_pool_lp_token.balanceOf(bob)) - - with boa.env.prank(bob): - for token in underlying_tokens: - token.approve(swap.address, 2**256 - 1) - - yield + approve_account(alice, pool_tokens, meta_swap) + mint_account(alice, pool_tokens, initial_balance, meta_initial_amounts) + mint_for_testing(bob, 1 * 10**18, None, True) + + add_base_pool_liquidity(alice, base_pool, base_pool_tokens, base_pool_decimals) + alice_bp_balance_norm = base_pool_lp_token.balanceOf(alice) / 10**18 + alice_mp_balance_norm = metapool_token.balanceOf(alice) / 10 ** metapool_token.decimals() + + if alice_mp_balance_norm < alice_bp_balance_norm: + mint_for_testing(alice, int(math.ceil(alice_bp_balance_norm) * 10 ** metapool_token.decimals()), metapool_token) + + with boa.env.prank(alice): + metapool_token.approve(meta_swap.address, 2**256 - 1) + base_pool_lp_token.approve(meta_swap.address, 2**256 - 1) + meta_swap.add_liquidity(deposit_meta_amounts, 0) + + add_base_pool_liquidity(bob, base_pool, base_pool_tokens, base_pool_decimals) + mint_for_testing(bob, initial_balance, metapool_token, False) + assert metapool_token.balanceOf(bob) == pytest.approx(base_pool_lp_token.balanceOf(bob)) + + with boa.env.prank(bob): + for underlying_token in underlying_tokens: + underlying_token.approve(meta_swap.address, 2**256 - 1) + + +@pytest.fixture() +def initial_setup(pool_type, request, metapool_token_type, pool_token_types, initial_decimals): + """ + Set up the initial state for a pool test. + Run either basic_setup or meta_setup depending on the pool_type. + """ + assert metapool_token_type is not None and pool_token_types and initial_decimals, "Fixtures required downstream" + fixture_name = {POOL_TYPES["basic"]: "basic_setup", POOL_TYPES["meta"]: "meta_setup"}[pool_type] + return request.getfixturevalue(fixture_name) diff --git a/tests/fixtures/constants.py b/tests/fixtures/constants.py index f7d3d228..a6428dd5 100644 --- a/tests/fixtures/constants.py +++ b/tests/fixtures/constants.py @@ -3,46 +3,56 @@ INITIAL_AMOUNT = 3_000_000 -@pytest.fixture(scope="module") +@pytest.fixture(scope="session") def initial_balance() -> int: return INITIAL_AMOUNT * 10**18 -@pytest.fixture(scope="module") -def initial_amounts(pool_type, decimals, meta_decimals) -> list[int]: - return ( - [INITIAL_AMOUNT * 10**precision for precision in decimals] - if pool_type == 0 - else [INITIAL_AMOUNT * 10**meta_decimals, INITIAL_AMOUNT * 10**18] - ) +@pytest.fixture() +def meta_initial_amounts(meta_decimals) -> list[int]: + return [INITIAL_AMOUNT * 10**meta_decimals, INITIAL_AMOUNT * 10**18] -@pytest.fixture(scope="module") -def deposit_amounts( - initial_amounts: list[int], pool_type, pool_token_types, metapool_token_type, pool_tokens, underlying_tokens +@pytest.fixture() +def basic_initial_amounts(decimals) -> list[int]: + return [INITIAL_AMOUNT * 10**precision for precision in decimals] + + +@pytest.fixture() +def initial_amounts(pool_type, basic_initial_amounts, meta_initial_amounts) -> list[int]: + return basic_initial_amounts if pool_type == 0 else meta_initial_amounts + + +@pytest.fixture() +def deposit_basic_amounts(initial_amounts: list[int], pool_token_types, pool_tokens) -> list[int]: + return [ + initial_amounts[i] * 10**18 // pool_token.exchangeRate() // 2 + if pool_token_type == 1 + else initial_amounts[i] // 2 + for i, (pool_token_type, pool_token) in enumerate(zip(pool_token_types, pool_tokens)) + ] + + +@pytest.fixture() +def deposit_meta_amounts( + meta_initial_amounts: list[int], metapool_token_type, pool_tokens, underlying_tokens ) -> list[int]: - amounts = [] + return [ + meta_initial_amounts[0] // 2 + if metapool_token_type != 1 + else meta_initial_amounts[0] * 10**18 // underlying_tokens[0].exchangeRate() // 2, + meta_initial_amounts[1] // 2, + ] + +@pytest.fixture() +def deposit_amounts(deposit_basic_amounts, deposit_meta_amounts, pool_type) -> list[int]: # This (almost) adds liquidity in balance for oracle tokens if pool_type == 0: - i = 0 - for ptt, pt in zip(pool_token_types, pool_tokens): - if ptt != 1: - amounts.append(initial_amounts[i] // 2) - else: - amounts.append(initial_amounts[i] * 10**18 // pt.exchangeRate() // 2) - i += 1 - else: - if metapool_token_type != 1: - amounts.append(initial_amounts[0] // 2) - else: - amounts.append(initial_amounts[0] * 10**18 // underlying_tokens[0].exchangeRate() // 2) - - amounts.append(initial_amounts[1] // 2) - - return amounts + return deposit_basic_amounts + return deposit_meta_amounts -@pytest.fixture(scope="module") +@pytest.fixture(scope="session") def zero_address() -> str: return "0x0000000000000000000000000000000000000000" diff --git a/tests/fixtures/contracts.py b/tests/fixtures/contracts.py new file mode 100644 index 00000000..50a003e0 --- /dev/null +++ b/tests/fixtures/contracts.py @@ -0,0 +1,82 @@ +import boa +import pytest + + +@pytest.fixture(scope="session") +def base_pool_deployer(): + return boa.load_partial("contracts/mocks/CurvePool.vy") + + +@pytest.fixture(scope="session") +def erc20_deployer(): + return boa.load_partial("contracts/mocks/ERC20.vy") + + +@pytest.fixture(scope="session") +def erc20_rebasing_deployer(): + return boa.load_partial("contracts/mocks/ERC20Rebasing.vy") + + +@pytest.fixture(scope="session") +def erc4626_deployer(): + return boa.load_partial("contracts/mocks/ERC4626.vy") + + +@pytest.fixture(scope="session") +def erc20oracle_deployer(): + return boa.load_partial("contracts/mocks/ERC20Oracle.vy") + + +@pytest.fixture(scope="session") +def erc20rebasing_conditional_deployer(): + return boa.load_partial("contracts/mocks/ERC20RebasingConditional.vy") + + +@pytest.fixture(scope="session") +def curve_token_v3_deployer(): + return boa.load_partial("contracts/mocks/CurveTokenV3.vy") + + +@pytest.fixture(scope="session") +def zap_deployer(): + return boa.load_partial("contracts/mocks/Zap.vy") + + +@pytest.fixture(scope="session") +def meta_zap_ng_deployer(): + return boa.load_partial("contracts/main/MetaZapNG.vy") + + +@pytest.fixture(scope="session") +def gauge_deployer(): + return boa.load_partial("contracts/main/LiquidityGauge.vy") + + +@pytest.fixture(scope="session") +def amm_deployer(): + return boa.load_partial("contracts/main/CurveStableSwapNG.vy") + + +@pytest.fixture(scope="session") +def meta_deployer(): + return boa.load_partial("contracts/main/CurveStableSwapMetaNG.vy") + + +@pytest.fixture(scope="session") +def factory_deployer(): + return boa.load_partial("contracts/main/CurveStableSwapFactoryNG.vy") + + +@pytest.fixture(scope="session") +def views_deployer(): + return boa.load_partial("contracts/main/CurveStableSwapNGViews.vy") + + +@pytest.fixture(scope="session") +def math_deployer(): + return boa.load_partial("contracts/main/CurveStableSwapNGMath.vy") + + +@pytest.fixture(scope="session") +def callback_swap_deployer(): + return boa.load_partial("contracts/mocks/CallbackSwap.vy") diff --git a/tests/fixtures/factory.py b/tests/fixtures/factory.py index 8f4baf72..72d47672 100644 --- a/tests/fixtures/factory.py +++ b/tests/fixtures/factory.py @@ -2,127 +2,92 @@ import pytest -@pytest.fixture(scope="module") -def gauge_interface(): - return boa.load_partial("contracts/main/LiquidityGauge.vy") - - -@pytest.fixture(scope="module") -def gauge_implementation(deployer, gauge_interface): +@pytest.fixture() +def gauge_implementation(deployer, gauge_deployer): with boa.env.prank(deployer): - return gauge_interface.deploy_as_blueprint() - + return gauge_deployer.deploy_as_blueprint() -@pytest.fixture(scope="module") -def amm_interface(): - return boa.load_partial("contracts/main/CurveStableSwapNG.vy") - -@pytest.fixture(scope="module") -def amm_implementation(deployer, amm_interface): +@pytest.fixture() +def amm_implementation(deployer, amm_deployer): with boa.env.prank(deployer): - impl = amm_interface.deploy_as_blueprint() - return impl - - -@pytest.fixture(scope="module") -def amm_interface_meta(): - return boa.load_partial("contracts/main/CurveStableSwapMetaNG.vy") + return amm_deployer.deploy_as_blueprint() -@pytest.fixture(scope="module") -def amm_implementation_meta(deployer, amm_interface_meta): +@pytest.fixture() +def amm_implementation_meta(deployer, meta_deployer): with boa.env.prank(deployer): - impl = amm_interface_meta.deploy_as_blueprint() - return impl + return meta_deployer.deploy_as_blueprint() -@pytest.fixture(scope="module") -def views_implementation(deployer): +@pytest.fixture() +def views_implementation(deployer, views_deployer): with boa.env.prank(deployer): - return boa.load("contracts/main/CurveStableSwapNGViews.vy") + return views_deployer.deploy() -@pytest.fixture(scope="module") -def math_implementation(deployer): +@pytest.fixture() +def math_implementation(deployer, math_deployer): with boa.env.prank(deployer): - return boa.load("contracts/main/CurveStableSwapNGMath.vy") + return math_deployer.deploy() -@pytest.fixture(scope="module") +@pytest.fixture() def factory( - deployer, - fee_receiver, - owner, - gauge_implementation, - views_implementation, - math_implementation, + deployer, fee_receiver, owner, gauge_implementation, views_implementation, math_implementation, factory_deployer ): with boa.env.prank(deployer): - _factory = boa.load( - "contracts/main/CurveStableSwapFactoryNG.vy", - fee_receiver, - owner, - ) + factory = factory_deployer.deploy(fee_receiver, owner) with boa.env.prank(owner): - _factory.set_gauge_implementation(gauge_implementation.address) - _factory.set_views_implementation(views_implementation.address) - _factory.set_math_implementation(math_implementation.address) + factory.set_gauge_implementation(gauge_implementation.address) + factory.set_views_implementation(views_implementation.address) + factory.set_math_implementation(math_implementation.address) - return _factory + return factory # <--------------------- Functions ---------------------> -@pytest.fixture(scope="module") +@pytest.fixture() def set_pool_implementations(owner, factory, amm_implementation): with boa.env.prank(owner): factory.set_pool_implementations(0, amm_implementation.address) -@pytest.fixture(scope="module") +@pytest.fixture() def set_metapool_implementations(owner, factory, amm_implementation_meta): with boa.env.prank(owner): factory.set_metapool_implementations(0, amm_implementation_meta.address) -@pytest.fixture(scope="module") -def add_base_pool( - owner, - factory, - base_pool, - base_pool_lp_token, - base_pool_tokens, -): +@pytest.fixture() +def add_base_pool(owner, factory, base_pool, base_pool_lp_token, base_pool_tokens): with boa.env.prank(owner): factory.add_base_pool( - base_pool.address, - base_pool_lp_token.address, - [0] * len(base_pool_tokens), - len(base_pool_tokens), + base_pool.address, base_pool_lp_token.address, [0] * len(base_pool_tokens), len(base_pool_tokens) ) -@pytest.fixture(scope="module") +@pytest.fixture() def set_gauge_implementation(owner, factory, gauge_implementation): with boa.env.prank(owner): factory.set_gauge_implementation(gauge_implementation.address) -@pytest.fixture(scope="module") +@pytest.fixture() def set_views_implementation(owner, factory, views_implementation): with boa.env.prank(owner): factory.set_views_implementation(views_implementation.address) -@pytest.fixture(scope="module") +@pytest.fixture() def set_math_implementation(owner, factory, math_implementation): with boa.env.prank(owner): factory.set_math_implementation(math_implementation.address) -@pytest.fixture(scope="module") -def gauge(owner, factory, swap, gauge_interface, set_gauge_implementation): +@pytest.fixture() +def gauge(owner, factory, swap, gauge_deployer, set_gauge_implementation): with boa.env.prank(owner): gauge_address = factory.deploy_gauge(swap.address) - return gauge_interface.at(gauge_address) + return gauge_deployer.at(gauge_address) diff --git a/tests/fixtures/mocks.py b/tests/fixtures/mocks.py index 7555d1cb..148b1b9a 100644 --- a/tests/fixtures/mocks.py +++ b/tests/fixtures/mocks.py @@ -2,12 +2,11 @@ import pytest -@pytest.fixture(scope="module") -def callback_contract(bob, swap, pool_tokens, underlying_tokens): - +@pytest.fixture() +def callback_contract(bob, swap, pool_tokens, underlying_tokens, callback_swap_deployer): with boa.env.prank(bob): - _callback = boa.load("contracts/mocks/CallbackSwap.vy", swap.address, bob) + callback = callback_swap_deployer.deploy(swap.address, bob) for token in pool_tokens + underlying_tokens: - token.approve(_callback.address, 2**256 - 1) + token.approve(callback.address, 2**256 - 1) - return _callback + return callback diff --git a/tests/fixtures/pools.py b/tests/fixtures/pools.py index 2ec0edc6..64ca9399 100644 --- a/tests/fixtures/pools.py +++ b/tests/fixtures/pools.py @@ -2,125 +2,113 @@ import pytest from eth_utils import function_signature_to_4byte_selector +from tests.constants import POOL_TYPES -@pytest.fixture(scope="module") -def swap( - deployer, - factory, - pool_size, - pool_type, - pool_token_types, - metapool_token_type, - pool_tokens, - zero_address, - amm_interface, - set_pool_implementations, - underlying_tokens, - base_pool, - amm_interface_meta, - add_base_pool, - set_metapool_implementations, -): - oracle_method_id = function_signature_to_4byte_selector("exchangeRate()") - offpeg_fee_multiplier = 20000000000 - if pool_type == 0: - A = 2000 - fee = 1000000 - method_ids = [bytes(b"")] * pool_size - oracles = [zero_address] * pool_size - asset_types = [] +ORACLE_METHOD_ID = function_signature_to_4byte_selector("exchangeRate()") +OFFPEG_FEE_MULTIPLIER = 20000000000 - for i in range(len(pool_tokens)): - asset_type = pool_tokens[i].asset_type() +@pytest.fixture() +def basic_swap(deployer, factory, pool_size, pool_tokens, zero_address, amm_deployer, set_pool_implementations): + A = 2000 + fee = 1000000 + method_ids = [b""] * pool_size + oracles = [zero_address] * pool_size - if asset_type == 0: + for i, token in enumerate(pool_tokens): + match token.asset_type(): + case 0: # Plain A = 2000 fee = 1000000 - asset_types.append(asset_type) - elif asset_type == 1: + case 1: # Oracle A = 1000 fee = 3000000 - asset_types.append(asset_type) - method_ids[i] = oracle_method_id - oracles[i] = pool_tokens[i].address - elif asset_type == 2: + method_ids[i] = ORACLE_METHOD_ID + oracles[i] = token.address + case 2: # Rebasing A = 500 fee = 4000000 - asset_types.append(asset_type) - - with boa.env.prank(deployer): - pool = factory.deploy_plain_pool( - "test", - "test", - [t.address for t in pool_tokens], - A, - fee, - offpeg_fee_multiplier, - 866, - 0, - asset_types, - method_ids, - oracles, - ) - return amm_interface.at(pool) - - elif pool_type == 1: - A = 2000 - fee = 1000000 - method_id = bytes(b"") - oracle = zero_address - - metapool_token = underlying_tokens[0] - asset_type = metapool_token.asset_type() # 0 = Plain, 1 = Oracle, 2 = Rebasing - - if asset_type == 0: - A = 2000 - fee = 1000000 - - elif asset_type == 1: - A = 1000 - fee = 3000000 - method_id = oracle_method_id - oracle = metapool_token.address - - elif asset_type == 2: - A = 500 - fee = 4000000 - - pool = factory.deploy_metapool( - base_pool.address, # _base_pool: address - "test", # _name: String[32], - "test", # _symbol: String[10], - metapool_token.address, # _coin: address, - A, # _A: uint256, - fee, # _fee: uint256, - offpeg_fee_multiplier, - 866, # _ma_exp_time: uint256, - 0, # _implementation_idx: uint256 - asset_type, # _asset_type: uint8 - method_id, # _method_id: bytes4 - oracle, # _oracle: address + + with boa.env.prank(deployer): + ma_exp_time = 866 + implementation_idx = 0 + asset_types = [t.asset_type() for t in pool_tokens] + coins = [t.address for t in pool_tokens] + + pool = factory.deploy_plain_pool( + "test", + "test", + coins, + A, + fee, + OFFPEG_FEE_MULTIPLIER, + ma_exp_time, + implementation_idx, + asset_types, + method_ids, + oracles, ) + return amm_deployer.at(pool) - return amm_interface_meta.at(pool) - else: - raise ValueError("Wrong pool type") +@pytest.fixture() +def meta_swap( + factory, set_metapool_implementations, zero_address, metapool_token, base_pool, meta_deployer, add_base_pool +): + A = 2000 + fee = 1000000 + method_id = bytes(b"") + oracle = zero_address + + asset_type = metapool_token.asset_type() # 0 = Plain, 1 = Oracle, 2 = Rebasing + + if asset_type == 0: + A = 2000 + fee = 1000000 + + elif asset_type == 1: + A = 1000 + fee = 3000000 + method_id = ORACLE_METHOD_ID + oracle = metapool_token.address + + elif asset_type == 2: + A = 500 + fee = 4000000 + + pool = factory.deploy_metapool( + base_pool.address, # _base_pool: address + "test", # _name: String[32], + "test", # _symbol: String[10], + metapool_token.address, # _coin: address, + A, # _A: uint256, + fee, # _fee: uint256, + OFFPEG_FEE_MULTIPLIER, + 866, # _ma_exp_time: uint256, + 0, # _implementation_idx: uint256 + asset_type, # _asset_type: uint8 + method_id, # _method_id: bytes4 + oracle, # _oracle: address + ) + + return meta_deployer.at(pool) + + +@pytest.fixture() +def swap(request, pool_type, pool_token_types, initial_decimals, metapool_token_type): + assert all( + fixture is not None for fixture in (initial_decimals, pool_token_types, metapool_token_type) + ), "Fixtures required downstream" + fixture_name = {POOL_TYPES["basic"]: "basic_swap", POOL_TYPES["meta"]: "meta_swap"}[pool_type] + return request.getfixturevalue(fixture_name) # <--------------------- Metapool configuration ---------------------> -@pytest.fixture(scope="module") -def base_pool(deployer, owner, alice, base_pool_decimals, base_pool_tokens, base_pool_lp_token, zero_address): +@pytest.fixture() +def base_pool(deployer, owner, alice, base_pool_tokens, base_pool_lp_token, base_pool_deployer): with boa.env.prank(deployer): - base_pool = boa.load( - "contracts/mocks/CurvePool.vy", - owner, - [t.address for t in base_pool_tokens], - base_pool_lp_token.address, - 200, - 3000000, - 5000000000, + base_pool = base_pool_deployer.deploy( + owner, [t.address for t in base_pool_tokens], base_pool_lp_token.address, 200, 3000000, 5000000000 ) base_pool_lp_token.set_minter(base_pool.address) return base_pool diff --git a/tests/fixtures/tokens.py b/tests/fixtures/tokens.py index 2a98324b..c0d44ab5 100644 --- a/tests/fixtures/tokens.py +++ b/tests/fixtures/tokens.py @@ -1,129 +1,104 @@ import boa import pytest +from tests.constants import TOKEN_TYPES +from tests.fixtures.accounts import mint_account -@pytest.fixture(scope="module") -def plain_tokens(deployer, decimals): - tokens = [] + +@pytest.fixture() +def plain_tokens(erc20_deployer, deployer, decimals): with boa.env.prank(deployer): - for i, d in enumerate(decimals): - tokens.append(boa.load("contracts/mocks/ERC20.vy", f"TKN{i}", f"TKN{i}", decimals[i])) - return tokens + return [erc20_deployer.deploy(f"TKN{i}", f"TKN{i}", decimals[i]) for i, d in enumerate(decimals)] -@pytest.fixture(scope="module") -def oracle_tokens(deployer, decimals): - tokens = [] - with boa.env.prank(deployer): - tokens.append( - boa.load( - "contracts/mocks/ERC20Oracle.vy", - "OTA", - "OTA", - 18, - 1006470359024000000, - ) - ) - tokens.append( - boa.load( - "contracts/mocks/ERC20Oracle.vy", - "OTB", - "OTB", - 18, - 1007580460035000000, - ) - ) - return tokens - - -@pytest.fixture(scope="module") -def rebase_tokens(deployer, decimals): - tokens = [] +@pytest.fixture() +def oracle_tokens(erc20oracle_deployer, deployer, decimals): with boa.env.prank(deployer): - for i, d in enumerate(decimals): - tokens.append(boa.load("contracts/mocks/ERC20Rebasing.vy", f"OR_TKN{i}", f"OR_TKN{i}", decimals[i], True)) - return tokens - + return [ + erc20oracle_deployer.deploy("OTA", "OTA", 18, 1006470359024000000), + erc20oracle_deployer.deploy("OTB", "OTB", 18, 1007580460035000000), + ] -@pytest.fixture(scope="module") -def pool_tokens(pool_token_types, plain_tokens, oracle_tokens, rebase_tokens): - pool_tokens = [] - for i, t in enumerate(pool_token_types): - if t == 0: - pool_tokens.append(plain_tokens[i]) - elif t == 1: - pool_tokens.append(oracle_tokens[i]) - elif t == 2: - pool_tokens.append(rebase_tokens[i]) - else: - raise ValueError("Wrong pool token type") - return pool_tokens +@pytest.fixture() +def rebasing_tokens(erc20_rebasing_deployer, deployer, decimals): + with boa.env.prank(deployer): + return [ + erc20_rebasing_deployer.deploy(f"OR_TKN{i}", f"OR_TKN{i}", decimals[i], True) + for i, d in enumerate(decimals) + ] + + +@pytest.fixture() +def pool_tokens(pool_token_types, request, initial_decimals): + assert initial_decimals, "Fixture required for requesting `decimals` downstream" + fixtures = { + TOKEN_TYPES["plain"]: "plain_tokens", + TOKEN_TYPES["oracle"]: "oracle_tokens", + TOKEN_TYPES["rebasing"]: "rebasing_tokens", + } + type1, type2 = pool_token_types + first, _ = request.getfixturevalue(fixtures[type1]) + _, second = request.getfixturevalue(fixtures[type2]) + return [first, second] # <--------------------- Metapool configuration ---------------------> -@pytest.fixture(scope="module") -def metapool_token(metapool_token_type, plain_tokens, oracle_tokens, rebase_tokens): - if metapool_token_type == 0: - return plain_tokens[0] - elif metapool_token_type == 1: - return oracle_tokens[0] - elif metapool_token_type == 2: - return rebase_tokens[0] - else: - raise ValueError("Wrong pool token type") - - -@pytest.fixture(scope="module") +@pytest.fixture() +def metapool_token(metapool_token_type, request, initial_decimals, pool_token_types): + assert initial_decimals and pool_token_types, "Fixtures required for requesting `decimals` downstream" + fixture = { + TOKEN_TYPES["plain"]: "plain_tokens", + TOKEN_TYPES["oracle"]: "oracle_tokens", + TOKEN_TYPES["rebasing"]: "rebasing_tokens", + } + metapool_token, _ = request.getfixturevalue(fixture[metapool_token_type]) + return metapool_token + + +@pytest.fixture() def base_pool_decimals(): return [18, 18, 18] -@pytest.fixture(scope="module") -def base_pool_tokens(deployer, base_pool_decimals): - tokens = [] +@pytest.fixture() +def base_pool_tokens(erc20_deployer, deployer, base_pool_decimals): with boa.env.prank(deployer): - tokens.append(boa.load("contracts/mocks/ERC20.vy", "DAI", "DAI", base_pool_decimals[0])) - tokens.append(boa.load("contracts/mocks/ERC20.vy", "USDC", "USDC", base_pool_decimals[1])) - tokens.append(boa.load("contracts/mocks/ERC20.vy", "USDT", "USDT", base_pool_decimals[2])) - return tokens + return [erc20_deployer.deploy(c, c, base_pool_decimals[i]) for i, c in enumerate(("DAI", "USDC", "USDT"))] -@pytest.fixture(scope="module") -def base_pool_lp_token(deployer): +@pytest.fixture() +def base_pool_lp_token(deployer, curve_token_v3_deployer): with boa.env.prank(deployer): - return boa.load("contracts/mocks/CurveTokenV3.vy", "LP", "LP") + return curve_token_v3_deployer.deploy("LP", "LP") -@pytest.fixture(scope="module") +@pytest.fixture() def underlying_tokens(metapool_token, base_pool_tokens, base_pool_lp_token): return [metapool_token, base_pool_lp_token, *base_pool_tokens] # <--------------------- Gauge rewards ---------------------> -@pytest.fixture(scope="module") -def coin_reward(owner): +@pytest.fixture() +def coin_reward(owner, erc20_deployer): with boa.env.prank(owner): - return boa.load("contracts/mocks/ERC20.vy", "CR", "CR", 18) + return erc20_deployer.deploy("CR", "CR", 18) -@pytest.fixture(scope="module") -def coin_reward_a(owner, mint_owner): +@pytest.fixture() +def coin_reward_a(owner, erc20_deployer, pool_tokens, initial_balance, initial_amounts): + mint_account(owner, pool_tokens, initial_balance, initial_amounts) with boa.env.prank(owner): - return boa.load("contracts/mocks/ERC20.vy", "CRa", "CRa", 18) + return erc20_deployer.deploy("CRa", "CRa", 18) -@pytest.fixture(scope="module") -def coin_reward_b(owner): +@pytest.fixture() +def coin_reward_b(owner, erc20_deployer): with boa.env.prank(owner): - return boa.load("contracts/mocks/ERC20.vy", "CRb", "CRb", 18) + return erc20_deployer.deploy("CRb", "CRb", 18) -@pytest.fixture(scope="module") -def coin_rewards_additional(owner): - coins = [] +@pytest.fixture() +def coin_rewards_additional(owner, erc20_deployer): with boa.env.prank(owner): - for i in range(8): - coins.append(boa.load("contracts/mocks/ERC20.vy", f"CR{i}", f"CR{i}", 18)) - - return coins + return [erc20_deployer.deploy(f"CR{i}", f"CR{i}", 18) for i in range(8)] diff --git a/tests/gauge/__init__.py b/tests/gauge/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/gauge/test_rewards.py b/tests/gauge/test_rewards.py index 450ee3f8..48921dc0 100644 --- a/tests/gauge/test_rewards.py +++ b/tests/gauge/test_rewards.py @@ -6,34 +6,34 @@ LP_AMOUNT = 10**18 -@pytest.mark.usefixtures("forked_chain") -class TestGaugeRewards: - class TestAddRewards: - @pytest.fixture() - def initial_setup(self, owner, gauge, swap, add_initial_liquidity_owner, set_gauge_implementation): - with boa.env.prank(owner): - swap.approve(gauge.address, LP_AMOUNT) - gauge.deposit(LP_AMOUNT) - - def test_set_rewards_no_deposit(self, owner, coin_reward, swap, gauge, zero_address): - with boa.env.prank(owner): - gauge.add_reward(coin_reward.address, owner) - - assert swap.balanceOf(gauge.address) == LP_AMOUNT - assert gauge.reward_tokens(0) == coin_reward.address - assert gauge.reward_tokens(1) == zero_address - - def test_multiple_reward_tokens(self, owner, coin_reward, coin_reward_a, coin_reward_b, gauge): - coins = [coin_reward.address, coin_reward_a.address, coin_reward_b.address] - with boa.env.prank(owner): - for coin in coins: - gauge.add_reward(coin, owner) - - assert coins == [gauge.reward_tokens(i) for i in range(3)] - - def test_cant_exceed_max(self, owner, coin_rewards_additional, gauge): - with boa.env.prank(owner): - for i in range(8): - gauge.add_reward(coin_rewards_additional[i].address, owner) - with boa.reverts(): - gauge.add_reward(coin_rewards_additional[i].address, owner) +@pytest.fixture(autouse=True) +def initial_setup(forked_chain, factory, owner, gauge, swap, add_initial_liquidity_owner): + with boa.env.prank(owner): + swap.approve(gauge.address, LP_AMOUNT) + gauge.deposit(LP_AMOUNT) + + +def test_set_rewards_no_deposit(owner, coin_reward, swap, gauge, zero_address): + with boa.env.prank(owner): + gauge.add_reward(coin_reward.address, owner) + + assert swap.balanceOf(gauge.address) == LP_AMOUNT + assert gauge.reward_tokens(0) == coin_reward.address + assert gauge.reward_tokens(1) == zero_address + + +def test_multiple_reward_tokens(owner, coin_reward, coin_reward_a, coin_reward_b, gauge): + coins = [coin_reward.address, coin_reward_a.address, coin_reward_b.address] + with boa.env.prank(owner): + for coin in coins: + gauge.add_reward(coin, owner) + + assert coins == [gauge.reward_tokens(i) for i in range(3)] + + +def test_cant_exceed_max(owner, coin_rewards_additional, gauge): + with boa.env.prank(owner): + for i in range(8): + gauge.add_reward(coin_rewards_additional[i].address, owner) + with boa.reverts(): + gauge.add_reward(coin_rewards_additional[i].address, owner) diff --git a/tests/pools/__init__.py b/tests/pools/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/pools/exchange/conftest.py b/tests/pools/exchange/conftest.py new file mode 100644 index 00000000..2c8567d0 --- /dev/null +++ b/tests/pools/exchange/conftest.py @@ -0,0 +1,16 @@ +import pytest + +from tests.constants import TOKEN_TYPES +from tests.utils import get_asset_types_in_pool + + +@pytest.fixture() +def contains_rebasing_tokens(swap): + if TOKEN_TYPES["rebasing"] not in get_asset_types_in_pool(swap): + pytest.skip("Test requires pools with no rebasing tokens") + + +@pytest.fixture() +def skip_rebasing_tokens(swap): + if TOKEN_TYPES["rebasing"] in get_asset_types_in_pool(swap): + pytest.skip("Test requires pools with rebasing tokens") diff --git a/tests/pools/exchange/test_exchange.py b/tests/pools/exchange/test_exchange.py new file mode 100644 index 00000000..99c21fac --- /dev/null +++ b/tests/pools/exchange/test_exchange.py @@ -0,0 +1,84 @@ +import pytest + +pytestmark = pytest.mark.usefixtures("initial_setup") + + +@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) +def test_min_dy( + bob, + swap, + pool_type, + pool_tokens, + underlying_tokens, + pool_token_types, + metapool_token_type, + sending, + receiving, + decimals, +): + amount = 1000 * 10 ** decimals[sending] + initial_receiving = ( + pool_tokens[receiving].balanceOf(bob) if pool_type == 0 else underlying_tokens[receiving].balanceOf(bob) + ) + + min_dy = swap.get_dy(sending, receiving, amount) + # apply rebasing for expected dy + # Down rebasing breaks dy + if pool_type == 0 and pool_token_types[sending] == 2 and sending == 1: + min_dy -= pool_tokens[sending].balanceOf(swap.address) // 1000000 + + swap.exchange(sending, receiving, amount, min_dy - 1, sender=bob) + + if pool_type == 0: + received = pool_tokens[receiving].balanceOf(bob) + else: + received = underlying_tokens[receiving].balanceOf(bob) + + if (pool_type == 0 and 2 in pool_token_types) or (pool_type == 1 and metapool_token_type == 2): + assert abs(received - min_dy - initial_receiving) == pytest.approx(1, abs=received // 1000000) + else: + assert abs(received - min_dy - initial_receiving) <= 1 + + +@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) +def test_min_dy_imbalanced( + bob, + swap, + pool_type, + pool_tokens, + underlying_tokens, + pool_token_types, + metapool_token_type, + sending, + receiving, + decimals, +): + amounts = [1_500_000 * 10**i for i in decimals] + scaler = amounts.copy() # used to scale token amounts when decimals are different + + amounts[sending] = 0 + amounts[receiving] = amounts[receiving] + + swap.add_liquidity(amounts, 0, sender=bob) + + # oracle + rate = 1 + if pool_type == 0: + if pool_token_types[sending] == 1: + rate = rate / (pool_tokens[sending].exchangeRate() / 10**18) + if pool_token_types[receiving] == 1: + rate = rate * (pool_tokens[receiving].exchangeRate() / 10**18) + + elif pool_type == 1: + if metapool_token_type == 1: + if sending == 0: + rate = rate / (underlying_tokens[0].exchangeRate() / 10**18) + + if receiving == 0: + rate = rate * (underlying_tokens[0].exchangeRate() / 10**18) + + # we need to scale these appropriately for tokens with different decimal values + min_dy_sending = swap.get_dy(sending, receiving, scaler[sending]) / scaler[receiving] + min_dy_receiving = swap.get_dy(receiving, sending, scaler[receiving]) / scaler[sending] + + assert min_dy_sending * rate > min_dy_receiving diff --git a/tests/pools/test_exchange_received.py b/tests/pools/exchange/test_exchange_received.py similarity index 91% rename from tests/pools/test_exchange_received.py rename to tests/pools/exchange/test_exchange_received.py index 26f831a2..a9f72323 100644 --- a/tests/pools/test_exchange_received.py +++ b/tests/pools/exchange/test_exchange_received.py @@ -22,15 +22,12 @@ def transfer_and_swap( base_pool_decimals, ): def _transfer_and_swap(pool, sending: int, receiving: int, underlying: bool): - # get input and output tokens: sending_token = "swap" receiving_token = "swap" if pool_type == 1: - if underlying: - if sending == 0: input_coin = underlying_tokens[0] else: @@ -45,12 +42,10 @@ def _transfer_and_swap(pool, sending: int, receiving: int, underlying: bool): receiving_token = "base_pool" else: - input_coin = underlying_tokens[sending] output_coin = underlying_tokens[receiving] else: - input_coin = pool_tokens[sending] output_coin = pool_tokens[receiving] @@ -104,14 +99,8 @@ def _transfer_and_swap(pool, sending: int, receiving: int, underlying: bool): @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) -@pytest.mark.skip_rebasing_tokens def test_exchange_received_nonrebasing( - bob, - swap, - pool_tokens, - sending, - receiving, - transfer_and_swap, + bob, swap, pool_tokens, sending, receiving, transfer_and_swap, skip_rebasing_tokens ): swap_data = transfer_and_swap(swap, sending, receiving, False) @@ -122,17 +111,16 @@ def test_exchange_received_nonrebasing( assert swap_data["swap"]["receiving_token"][0] - swap_data["swap"]["receiving_token"][1] == swap_data["amount_out"] -@pytest.mark.skip_rebasing_tokens @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) -def test_exchange_not_received(bob, swap, pool_tokens, sending, receiving): +def test_exchange_not_received(bob, swap, pool_tokens, sending, receiving, skip_rebasing_tokens): with boa.env.prank(bob), boa.reverts(): swap.exchange_received(sending, receiving, 1, 0, bob) -@pytest.mark.skip_rebasing_tokens @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) -def test_exchange_received_no_dos(bob, charlie, swap, pool_tokens, sending, receiving, transfer_and_swap): - +def test_exchange_received_no_dos( + bob, charlie, swap, pool_tokens, sending, receiving, transfer_and_swap, skip_rebasing_tokens +): mint_for_testing(bob, 1, pool_tokens[sending], False) pool_tokens[sending].transfer(swap, 1, sender=bob) @@ -140,10 +128,10 @@ def test_exchange_received_no_dos(bob, charlie, swap, pool_tokens, sending, rece transfer_and_swap(swap, sending, receiving, False) -@pytest.mark.contains_rebasing_tokens @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) -def test_exchange_received_rebasing_reverts(bob, swap, transfer_and_swap, pool_tokens, sending, receiving): - +def test_exchange_received_rebasing_reverts( + bob, swap, transfer_and_swap, pool_tokens, sending, receiving, contains_rebasing_tokens +): if 2 in get_asset_types_in_pool(swap): with boa.reverts(): transfer_and_swap(swap, sending, receiving, False) diff --git a/tests/pools/exchange/test_exchange_receiver.py b/tests/pools/exchange/test_exchange_receiver.py new file mode 100644 index 00000000..ef03709b --- /dev/null +++ b/tests/pools/exchange/test_exchange_receiver.py @@ -0,0 +1,79 @@ +import pytest + +pytestmark = pytest.mark.usefixtures("initial_setup") + + +def test_add_liquidity(bob, charlie, swap, deposit_amounts): + swap.add_liquidity(deposit_amounts, 0, charlie, sender=bob) + + assert swap.balanceOf(bob) == 0 + assert swap.balanceOf(charlie) > 0 + + +def test_exchange( + bob, charlie, swap, pool_type, pool_tokens, underlying_tokens, decimals, pool_token_types, metapool_token_type +): + balance = pool_tokens[0].balanceOf(bob) if pool_type == 0 else underlying_tokens[0].balanceOf(bob) + + swap.exchange(1, 0, 1000 * 10**18, 0, charlie, sender=bob) + if pool_type == 0: + assert pool_tokens[0].balanceOf(charlie) > 0 + if pool_token_types[0] != 2: + assert pool_tokens[0].balanceOf(bob) == balance + else: + assert pool_tokens[0].balanceOf(bob) == pytest.approx(balance, rel=2e-2) + else: + assert underlying_tokens[0].balanceOf(charlie) > 0 + if metapool_token_type != 2: + assert underlying_tokens[0].balanceOf(bob) == balance + else: + assert underlying_tokens[0].balanceOf(bob) == pytest.approx(balance, rel=2e-2) + + +def test_remove_liquidity( + bob, swap, charlie, pool_type, pool_tokens, underlying_tokens, initial_amounts, pool_size, deposit_amounts +): + swap.add_liquidity(deposit_amounts, 0, sender=bob) + initial_amount = swap.balanceOf(bob) + withdraw_amount = initial_amount // 4 + swap.remove_liquidity(withdraw_amount, [0] * pool_size, charlie, sender=bob) + + i = 0 + if pool_type == 0: + for coin, amount in zip(pool_tokens, deposit_amounts): + assert coin.balanceOf(swap) + coin.balanceOf(charlie) == pytest.approx(deposit_amounts[0] * 2, rel=1.5e-2) + i += 1 + else: + for coin, amount in zip(underlying_tokens[:2], deposit_amounts): + assert coin.balanceOf(swap) + coin.balanceOf(charlie) == pytest.approx(deposit_amounts[0] * 2, rel=1.5e-2) + i += 1 + + assert swap.balanceOf(bob) == pytest.approx(deposit_amounts[0] * pool_size - withdraw_amount, rel=1.5e-2) + assert swap.totalSupply() == pytest.approx(deposit_amounts[0] * 2 * pool_size - withdraw_amount, rel=1.5e-2) + + +def test_remove_imbalanced( + bob, swap, charlie, pool_type, pool_tokens, underlying_tokens, initial_amounts, deposit_amounts +): + swap.add_liquidity(deposit_amounts, 0, sender=bob) + balance = swap.balanceOf(bob) + amounts = [i // 4 for i in initial_amounts] + swap.remove_liquidity_imbalance(amounts, balance, charlie, sender=bob) + + if pool_type == 0: + for i, coin in enumerate(pool_tokens): + assert coin.balanceOf(charlie) == pytest.approx(amounts[i], rel=1.5e-2) + assert coin.balanceOf(swap) == pytest.approx(initial_amounts[i] - amounts[i], rel=1.5e-2) + else: + for i, coin in enumerate(underlying_tokens[:2]): + assert coin.balanceOf(charlie) == pytest.approx(amounts[i], rel=1.5e-2) + assert coin.balanceOf(swap) == pytest.approx(initial_amounts[i] - amounts[i], rel=1.5e-2) + + assert swap.balanceOf(bob) / balance == pytest.approx(0.5, rel=1.5e-2) + + +def test_remove_one_coin(alice, charlie, swap, pool_tokens, underlying_tokens): + swap.remove_liquidity_one_coin(10**18, 0, 0, charlie, sender=alice) + + assert swap.balanceOf(charlie) == 0 + assert swap.balanceOf(alice) > 0 diff --git a/tests/pools/exchange/test_exchange_reverts.py b/tests/pools/exchange/test_exchange_reverts.py new file mode 100644 index 00000000..004b874a --- /dev/null +++ b/tests/pools/exchange/test_exchange_reverts.py @@ -0,0 +1,67 @@ +import boa +import pytest + +pytestmark = pytest.mark.usefixtures("initial_setup") + + +@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) +def test_insufficient_balance(charlie, pool_tokens, underlying_tokens, swap, sending, receiving, decimals): + amount = 10 ** decimals[sending] + + for token in pool_tokens + underlying_tokens: + assert token.balanceOf(charlie) == 0 + + # Charlie doesn't have any tokens, all balances are 0 + with boa.reverts(), boa.env.prank(charlie): + swap.exchange(sending, receiving, amount + 1, 0, sender=charlie) + + +@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) +def test_zero_amount_swap( + charlie, pool_tokens, underlying_tokens, swap, sending, receiving, decimals, contains_rebasing_tokens +): + with boa.reverts(): + swap.exchange(sending, receiving, 0, 0, sender=charlie) + + +@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) +def test_min_dy_too_high(bob, swap, sending, receiving, decimals): + amount = 10 ** decimals[sending] + min_dy = swap.get_dy(sending, receiving, amount) + with boa.reverts(): + swap.exchange(sending, receiving, amount, min_dy + 2, sender=bob) + + +@pytest.mark.parametrize("idx", range(2)) +def test_same_coin(bob, swap, idx): + with boa.reverts(): + swap.exchange(idx, idx, 0, 0, sender=bob) + + +@pytest.mark.parametrize("idx", [-1, -(2**127)]) +def test_i_below_zero(bob, swap, idx): + with boa.reverts(): + swap.exchange(idx, 0, 0, 0, sender=bob) + + +@pytest.mark.parametrize("idx", [9, 2**127 - 1]) +def test_i_above_n_coins(bob, swap, idx): + with boa.reverts(): + swap.exchange(idx, 0, 0, 0, sender=bob) + + +@pytest.mark.parametrize("idx", [-1, -(2**127)]) +def test_j_below_zero(bob, swap, idx): + with boa.reverts(): + swap.exchange(0, idx, 0, 0, sender=bob) + + +@pytest.mark.parametrize("idx", [9, 2**127 - 1]) +def test_j_above_n_coins(bob, swap, idx): + with boa.reverts(): + swap.exchange(0, idx, 0, 0, sender=bob) + + +def test_nonpayable(swap, bob): + with boa.reverts(): + swap.exchange(0, 1, 0, 0, sender=bob, value=1) diff --git a/tests/pools/general/test_donation_get_D.py b/tests/pools/general/test_donation_get_D.py new file mode 100644 index 00000000..2aa84334 --- /dev/null +++ b/tests/pools/general/test_donation_get_D.py @@ -0,0 +1,30 @@ +import boa + +from tests.utils import get_asset_types_in_pool +from tests.utils.tokens import mint_for_testing + + +def test_donate_get_D(bob, basic_swap, underlying_tokens, pool_tokens): + # check if pool is empty: + for i in range(basic_swap.N_COINS()): + assert basic_swap.balances(i) == 0 + + # adding liquidity should not bork: + amounts = [10**17] * basic_swap.N_COINS() + + for token in pool_tokens: + token.approve(basic_swap, 2**256 - 1, sender=bob) + mint_for_testing(bob, 10**18, token, False) + + # check if pool is empty (after minting tokenss): + for i in range(basic_swap.N_COINS()): + assert basic_swap.balances(i) == 0 + + # donate 1 wei and attempt adding liquidity: + pool_tokens[0].transfer(basic_swap, 10, sender=bob) + if 2 in get_asset_types_in_pool(basic_swap): + with boa.reverts(): + # division by zero error expected for rebasing implementation + basic_swap.add_liquidity(amounts, 0, sender=bob) + else: + basic_swap.add_liquidity(amounts, 0, sender=bob) diff --git a/tests/pools/test_erc4626_swaps.py b/tests/pools/general/test_erc4626_swaps.py similarity index 82% rename from tests/pools/test_erc4626_swaps.py rename to tests/pools/general/test_erc4626_swaps.py index 47467fe5..d3e962e3 100644 --- a/tests/pools/test_erc4626_swaps.py +++ b/tests/pools/general/test_erc4626_swaps.py @@ -9,7 +9,6 @@ def mint_vault_tokens(deposit_amount, underlying_token, vault_contract, user): - mint_for_testing(user, deposit_amount, underlying_token, False) underlying_token.approve(vault_contract, 2**256 - 1, sender=user) vault_contract.deposit(deposit_amount, user, sender=user) @@ -17,14 +16,12 @@ def mint_vault_tokens(deposit_amount, underlying_token, vault_contract, user): def donate_to_vault(donation_amount, underlying_token, vault_contract, user): - donation_amount = donation_amount * 10 ** underlying_token.decimals() mint_for_testing(user, donation_amount, underlying_token, False) underlying_token.transfer(vault_contract, donation_amount, sender=user) def mint_tokens(charlie, pool_erc20_tokens, pool_tokens, swap, i): - amount_erc20_in = 10 ** pool_erc20_tokens[i].decimals() if amount_erc20_in > pool_erc20_tokens[i].balanceOf(charlie): @@ -40,64 +37,41 @@ def mint_tokens(charlie, pool_erc20_tokens, pool_tokens, swap, i): return amount_in -@pytest.fixture(scope="module") -def asset(deployer): +@pytest.fixture() +def asset(deployer, erc20_deployer): with boa.env.prank(deployer): - return boa.load( - "contracts/mocks/ERC20.vy", - "Asset", - "AST", - 8, # 8 decimals - ) + return erc20_deployer.deploy("Asset", "AST", 8) # 8 decimals -@pytest.fixture(scope="module") -def token_a(deployer, asset): +@pytest.fixture() +def token_a(deployer, asset, erc4626_deployer): with boa.env.prank(deployer): - return boa.load( - "contracts/mocks/ERC4626.vy", - "Vault", - "VLT", - 18, # 8 decimals - asset.address, - ) + return erc4626_deployer.deploy("Vault", "VLT", 18, asset.address) # 8 decimals -@pytest.fixture(scope="module") -def token_b(deployer): +@pytest.fixture() +def token_b(deployer, erc20oracle_deployer): with boa.env.prank(deployer): - return boa.load( - "contracts/mocks/ERC20Oracle.vy", - "Oracle", - "ORC", - 18, - 1006470359024000000, - ) + return erc20oracle_deployer.deploy("Oracle", "ORC", 18, 1006470359024000000) -@pytest.fixture(scope="module") -def token_c(deployer): +@pytest.fixture() +def token_c(deployer, erc20rebasing_conditional_deployer): with boa.env.prank(deployer): - return boa.load( - "contracts/mocks/ERC20RebasingConditional.vy", - "Rebasing", - "RBSN", - 6, - True, - ) + return erc20rebasing_conditional_deployer.deploy("Rebasing", "RBSN", 6, True) -@pytest.fixture(scope="module") +@pytest.fixture() def pool_tokens(token_a, token_b, token_c): return [token_a, token_b, token_c] -@pytest.fixture(scope="module") +@pytest.fixture() def pool_erc20_tokens(asset, token_b, token_c): return [asset, token_b, token_c] -@pytest.fixture(scope="module") +@pytest.fixture() def asset_types(pool_tokens): _asset_types = [] for token in pool_tokens: @@ -112,16 +86,8 @@ def asset_types(pool_tokens): return _asset_types -@pytest.fixture(scope="module") -def empty_swap( - deployer, - factory, - pool_tokens, - zero_address, - amm_interface, - asset_types, - set_pool_implementations, -): +@pytest.fixture() +def empty_swap(deployer, factory, pool_tokens, zero_address, amm_deployer, asset_types, set_pool_implementations): pool_size = len(pool_tokens) oracle_method_id = function_signature_to_4byte_selector("exchangeRate()") offpeg_fee_multiplier = 20000000000 @@ -131,7 +97,6 @@ def empty_swap( fee = 3000000 for i in range(pool_size): - if asset_types[i] == 1: method_ids[i] = oracle_method_id oracles[i] = pool_tokens[i].address @@ -151,10 +116,10 @@ def empty_swap( oracles, ) - return amm_interface.at(pool) + return amm_deployer.at(pool) -@pytest.fixture(scope="module") +@pytest.fixture() def deposit_amounts(pool_erc20_tokens, token_a, bob): _deposit_amounts = [] for i, token in enumerate(pool_erc20_tokens): @@ -176,9 +141,8 @@ def deposit_amounts(pool_erc20_tokens, token_a, bob): return _deposit_amounts -@pytest.fixture(scope="module") +@pytest.fixture() def swap(empty_swap, bob, deposit_amounts, pool_tokens): - for token in pool_tokens: token.approve(empty_swap, 2**256 - 1, sender=bob) empty_swap.add_liquidity(deposit_amounts, 0, bob, sender=bob) @@ -187,7 +151,6 @@ def swap(empty_swap, bob, deposit_amounts, pool_tokens): @pytest.mark.parametrize("i,j", itertools.permutations(range(3), 2)) def test_swap(swap, i, j, charlie, pool_tokens, pool_erc20_tokens): - amount_in = mint_tokens(charlie, pool_erc20_tokens, pool_tokens, swap, i) if "RebasingConditional" in pool_tokens[i].filename: @@ -206,7 +169,6 @@ def test_swap(swap, i, j, charlie, pool_tokens, pool_erc20_tokens): @pytest.mark.parametrize("i,j", itertools.permutations(range(3), 2)) def test_donate_swap(swap, i, j, alice, charlie, pool_tokens, pool_erc20_tokens): - amount_in = mint_tokens(charlie, pool_erc20_tokens, pool_tokens, swap, i) # rebase: @@ -229,7 +191,6 @@ def test_donate_swap(swap, i, j, alice, charlie, pool_tokens, pool_erc20_tokens) def test_rebase(swap, charlie, bob, pool_tokens): - amount_rewards = 10**4 * 10**18 i = 1 if amount_rewards > pool_tokens[i].balanceOf(charlie): diff --git a/tests/pools/general/test_fees.py b/tests/pools/general/test_fees.py new file mode 100644 index 00000000..f1f62511 --- /dev/null +++ b/tests/pools/general/test_fees.py @@ -0,0 +1,75 @@ +import pytest + +pytestmark = pytest.mark.usefixtures("initial_setup") + + +@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) +def test_admin_balances(bob, swap, pool_type, pool_tokens, underlying_tokens, initial_amounts, sending, receiving): + for send, recv in [(sending, receiving), (receiving, sending)]: + swap.exchange(send, recv, initial_amounts[send], 0, sender=bob) + + for i in (sending, receiving): + if pool_type == 0: + admin_fee = pool_tokens[i].balanceOf(swap) - swap.balances(i) + assert admin_fee > 0 + else: + admin_fee = underlying_tokens[i].balanceOf(swap) - swap.balances(i) + assert admin_fee > 0 + + +@pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) +def test_withdraw_one_coin( + alice, bob, fee_receiver, swap, pool_type, pool_tokens, underlying_tokens, sending, receiving, initial_amounts +): + swap.exchange(sending, receiving, initial_amounts[sending], 0, sender=bob) + + admin_balance = swap.admin_balances(receiving) + + assert admin_balance > 0 + assert swap.admin_balances(sending) == 0 + + swap.withdraw_admin_fees(sender=alice) + swap_balance = ( + pool_tokens[receiving].balanceOf(swap) if pool_type == 0 else underlying_tokens[receiving].balanceOf(swap) + ) + assert swap.balances(receiving) == swap_balance + expected_balance = ( + pool_tokens[receiving].balanceOf(fee_receiver) + if pool_type == 0 + else underlying_tokens[receiving].balanceOf(fee_receiver) + ) + + assert admin_balance == pytest.approx(expected_balance, abs=1) # +- 1 + + +def test_no_fees(bob, fee_receiver, swap, pool_type, pool_tokens, underlying_tokens): + swap.withdraw_admin_fees(sender=bob) + + if pool_type == 0: + for coin in pool_tokens: + assert coin.balanceOf(fee_receiver) == 0 + else: + for coin in underlying_tokens: + assert coin.balanceOf(fee_receiver) == 0 + + +def test_withdraw_admin_fees(bob, swap, pool_type, pool_tokens, underlying_tokens, fee_receiver, decimals): + swap.exchange(1, 0, 10_000 * 10 ** decimals[1], 0, sender=bob) + + fees = [] + if pool_type == 0: + for i, coin in enumerate(pool_tokens): + assert coin.balanceOf(fee_receiver) == 0 + fees.append(swap.admin_balances(i)) + else: + for i, coin in enumerate(underlying_tokens[:2]): + assert coin.balanceOf(fee_receiver) == 0 + fees.append(swap.admin_balances(i)) + + swap.withdraw_admin_fees(sender=bob) + if pool_type == 0: + for i, coin in enumerate(pool_tokens): + assert coin.balanceOf(fee_receiver) == pytest.approx(fees[i], abs=1) + else: + for i, coin in enumerate(underlying_tokens[:2]): + assert coin.balanceOf(fee_receiver) == pytest.approx(fees[i], abs=1) diff --git a/tests/pools/test_ramp_A.py b/tests/pools/general/test_ramp_A.py similarity index 100% rename from tests/pools/test_ramp_A.py rename to tests/pools/general/test_ramp_A.py diff --git a/tests/pools/test_specific_liquidity_operations.py b/tests/pools/general/test_specific_liquidity_operations.py similarity index 74% rename from tests/pools/test_specific_liquidity_operations.py rename to tests/pools/general/test_specific_liquidity_operations.py index ee19969b..15285ff0 100644 --- a/tests/pools/test_specific_liquidity_operations.py +++ b/tests/pools/general/test_specific_liquidity_operations.py @@ -5,47 +5,30 @@ from tests.utils.tokens import mint_for_testing -@pytest.fixture(scope="module") -def token_a(deployer): +@pytest.fixture() +def token_a(deployer, erc20oracle_deployer): with boa.env.prank(deployer): - return boa.load( - "contracts/mocks/ERC20Oracle.vy", - "OTA", - "OTA", - 18, - 1006470359024000000, - ) + return erc20oracle_deployer.deploy("OTA", "OTA", 18, 1006470359024000000) -@pytest.fixture(scope="module") -def token_b(deployer): +@pytest.fixture() +def token_b(deployer, erc20oracle_deployer): with boa.env.prank(deployer): - return boa.load( - "contracts/mocks/ERC20Oracle.vy", - "OTB", - "OTB", - 18, - 1000000000000000000, - ) + return erc20oracle_deployer.deploy("OTB", "OTB", 18, 1000000000000000000) -@pytest.fixture(scope="module") -def token_c(deployer): +@pytest.fixture() +def token_c(deployer, erc20_deployer): with boa.env.prank(deployer): - return boa.load( - "contracts/mocks/ERC20.vy", - "OTC", - "OTC", - 18, - ) + return erc20_deployer.deploy("OTC", "OTC", 18) -@pytest.fixture(scope="module") +@pytest.fixture() def pool_tokens(token_a, token_b, token_c): return [token_a, token_b, token_c] -@pytest.fixture(scope="module") +@pytest.fixture() def asset_types(pool_tokens): _asset_types = [] for token in pool_tokens: @@ -58,16 +41,8 @@ def asset_types(pool_tokens): return _asset_types -@pytest.fixture(scope="module") -def empty_swap( - deployer, - factory, - pool_tokens, - zero_address, - amm_interface, - asset_types, - set_pool_implementations, -): +@pytest.fixture() +def empty_swap(deployer, factory, pool_tokens, zero_address, amm_deployer, asset_types, set_pool_implementations): pool_size = len(pool_tokens) oracle_method_id = function_signature_to_4byte_selector("exchangeRate()") offpeg_fee_multiplier = 20000000000 @@ -77,7 +52,6 @@ def empty_swap( fee = 3000000 for i in range(pool_size): - if asset_types[i] == 1: method_ids[i] = oracle_method_id oracles[i] = pool_tokens[i].address @@ -97,10 +71,10 @@ def empty_swap( oracles, ) - return amm_interface.at(pool) + return amm_deployer.at(pool) -@pytest.fixture(scope="module") +@pytest.fixture() def deposit_amounts(pool_tokens, bob): _deposit_amounts = [] for i, token in enumerate(pool_tokens): @@ -112,9 +86,8 @@ def deposit_amounts(pool_tokens, bob): return _deposit_amounts -@pytest.fixture(scope="module") +@pytest.fixture() def swap(empty_swap, bob, deposit_amounts, pool_tokens): - for token in pool_tokens: token.approve(empty_swap, 2**256 - 1, sender=bob) @@ -123,7 +96,6 @@ def swap(empty_swap, bob, deposit_amounts, pool_tokens): def test_swap(swap, charlie, pool_tokens): - amount_in = 10**18 i = 0 j = 1 @@ -135,7 +107,6 @@ def test_swap(swap, charlie, pool_tokens): def test_rebase(swap, charlie, bob, pool_tokens): - amount_rewards = 10**4 * 10**18 i = 1 if amount_rewards > pool_tokens[i].balanceOf(charlie): diff --git a/tests/pools/test_swap_getters.py b/tests/pools/general/test_swap_getters.py similarity index 72% rename from tests/pools/test_swap_getters.py rename to tests/pools/general/test_swap_getters.py index dfccf6e2..17f6aa4b 100644 --- a/tests/pools/test_swap_getters.py +++ b/tests/pools/general/test_swap_getters.py @@ -1,8 +1,8 @@ import pytest from boa.test import strategy -from hypothesis import given, settings +from hypothesis import HealthCheck, given, settings -SETTINGS = {"max_examples": 100, "deadline": None} +SETTINGS = {"max_examples": 100, "deadline": None, "suppress_health_check": [HealthCheck.function_scoped_fixture]} @given( @@ -12,7 +12,6 @@ ) @settings(**SETTINGS) def test_get_dx(i, j, amount_in, swap, factory, initial_setup): - n_coins = swap.N_COINS() if i == j or max(i, j) >= n_coins: return @@ -27,16 +26,14 @@ def test_get_dx(i, j, amount_in, swap, factory, initial_setup): assert _amount_in == pytest.approx(approx_in, 1e-2) -@pytest.mark.only_for_pool_type(1) # only for metapools @given( amount_in=strategy("decimal", min_value=0.001, max_value=10**6), i=strategy("uint", min_value=0, max_value=4), j=strategy("uint", min_value=0, max_value=4), ) @settings(**SETTINGS) -def test_get_dx_underlying(i, j, amount_in, swap, factory, initial_setup): - - base_n_coins = swap.BASE_N_COINS() +def test_get_dx_underlying(i, j, amount_in, meta_swap, factory, initial_setup): + base_n_coins = meta_swap.BASE_N_COINS() if i == j: return @@ -48,10 +45,10 @@ def test_get_dx_underlying(i, j, amount_in, swap, factory, initial_setup): if min(i, j) > 0: # base pool swap: it reverts in view contract return - _token_i_precision = 10 ** factory.get_underlying_decimals(swap)[i] + _token_i_precision = 10 ** factory.get_underlying_decimals(meta_swap)[i] _amount_in = int(amount_in * _token_i_precision) - expected_out = swap.get_dy_underlying(i, j, _amount_in) - approx_in = swap.get_dx_underlying(i, j, expected_out) + expected_out = meta_swap.get_dy_underlying(i, j, _amount_in) + approx_in = meta_swap.get_dx_underlying(i, j, expected_out) # not accurate, but close enough: assert _amount_in == pytest.approx(approx_in, 1e-2) diff --git a/tests/pools/test_virtual_price.py b/tests/pools/general/test_virtual_price.py similarity index 96% rename from tests/pools/test_virtual_price.py rename to tests/pools/general/test_virtual_price.py index 78c22783..28382a4b 100644 --- a/tests/pools/test_virtual_price.py +++ b/tests/pools/general/test_virtual_price.py @@ -53,19 +53,12 @@ def test_exchange(bob, swap, sending, receiving, decimals): virtual_price = swap.get_virtual_price() amount = 10_000 * 10 ** decimals[sending] - swap.exchange( - sending, - receiving, - amount, - 0, - sender=bob, - ) + swap.exchange(sending, receiving, amount, 0, sender=bob) assert swap.get_virtual_price() > virtual_price def test_donate_virtual_price(bob, swap, pool_tokens, initial_amounts, pool_size): - # make a deposit for i, amount in enumerate(initial_amounts): amounts = [0] * pool_size diff --git a/tests/pools/liquidity/test_add_liquidity.py b/tests/pools/liquidity/test_add_liquidity.py new file mode 100644 index 00000000..72a3ac28 --- /dev/null +++ b/tests/pools/liquidity/test_add_liquidity.py @@ -0,0 +1,150 @@ +import boa +import pytest + +from tests.fixtures.constants import INITIAL_AMOUNT +from tests.utils.transactions import call_returning_result_and_logs + +pytestmark = pytest.mark.usefixtures("initial_setup") + + +def test_add_liquidity( + bob, + swap, + pool_type, + pool_tokens, + underlying_tokens, + deposit_amounts, + initial_amounts, + pool_token_types, + metapool_token_type, +): + swap.add_liquidity(deposit_amounts, 0, sender=bob) + is_ideal = True + + if pool_type == 0: + for i, (pool_token, amount) in enumerate(zip(pool_tokens, deposit_amounts)): + if pool_token_types[i] == 2: + is_ideal = False + assert pool_token.balanceOf(bob) >= initial_amounts[i] - deposit_amounts[i] + assert pool_token.balanceOf(swap.address) >= deposit_amounts[i] * 2 + else: + assert pool_token.balanceOf(bob) == initial_amounts[i] - deposit_amounts[i] + assert pool_token.balanceOf(swap.address) == deposit_amounts[i] * 2 + + if pool_token_types[i] == 1: + is_ideal = False + + ideal = len(pool_tokens) * INITIAL_AMOUNT // 2 * 10**18 + if is_ideal: + assert abs(swap.balanceOf(bob) - ideal) <= 1 + assert abs(swap.totalSupply() - ideal * 2) <= 2 + else: + if metapool_token_type == 2: + assert underlying_tokens[0].balanceOf(bob) >= initial_amounts[0] - deposit_amounts[0] + assert underlying_tokens[0].balanceOf(swap.address) >= deposit_amounts[0] * 2 + else: + assert underlying_tokens[0].balanceOf(bob) == initial_amounts[0] - deposit_amounts[0] + assert underlying_tokens[0].balanceOf(swap.address) == deposit_amounts[0] * 2 + + if metapool_token_type == 0: + ideal = INITIAL_AMOUNT * 10**18 # // 2 * 2 + assert abs(swap.balanceOf(bob) - ideal) <= 1 + assert abs(swap.totalSupply() - ideal * 2) <= 2 + + assert underlying_tokens[1].balanceOf(bob) == initial_amounts[1] - deposit_amounts[1] + assert underlying_tokens[1].balanceOf(swap) == deposit_amounts[1] * 2 + + +@pytest.mark.parametrize("idx", (0, 1)) +def test_add_one_coin( + bob, + swap, + pool_type, + pool_tokens, + underlying_tokens, + deposit_amounts, + initial_amounts, + pool_token_types, + metapool_token_type, + idx, +): + amounts = [0] * len(pool_tokens) + amounts[idx] = deposit_amounts[idx] + + swap.add_liquidity(amounts, 0, sender=bob) + is_ideal = True + + if pool_type == 0: + for i, pool_token in enumerate(pool_tokens): + if pool_token_types[i] == 2: + is_ideal = False + assert pool_token.balanceOf(bob) >= initial_amounts[i] - amounts[i] - 1 + assert pool_token.balanceOf(swap.address) >= deposit_amounts[i] + amounts[i] - 1 + else: + assert pool_token.balanceOf(bob) == initial_amounts[i] - amounts[i] + assert pool_token.balanceOf(swap.address) == deposit_amounts[i] + amounts[i] + else: + if metapool_token_type == 2: + is_ideal = False + assert underlying_tokens[0].balanceOf(bob) >= initial_amounts[0] - amounts[0] - 1 + assert underlying_tokens[0].balanceOf(swap.address) >= deposit_amounts[0] + amounts[0] - 1 + else: + assert underlying_tokens[0].balanceOf(bob) == initial_amounts[0] - amounts[0] + assert underlying_tokens[0].balanceOf(swap) == deposit_amounts[0] + amounts[0] + + assert underlying_tokens[1].balanceOf(bob) == initial_amounts[1] - amounts[1] + assert underlying_tokens[1].balanceOf(swap) == deposit_amounts[1] + amounts[1] + + difference = abs(swap.balanceOf(bob) - deposit_amounts[idx]) + if is_ideal: + assert difference / (deposit_amounts[idx]) < 0.01 + else: + assert difference / (deposit_amounts[idx]) < 0.02 + + +def test_insufficient_balance(charlie, swap, pool_type, decimals, meta_decimals): + if pool_type == 0: + amounts = [(10**i) for i in decimals] + else: + amounts = [(10**i) for i in [meta_decimals, 18]] + + with boa.reverts(): # invalid approval or balance + swap.add_liquidity(amounts, 0, sender=charlie) + + +def test_min_amount_too_high(bob, swap, pool_type, deposit_amounts, pool_tokens): + size = 2 + if pool_type == 0: + size = len(pool_tokens) + + with boa.reverts(): + swap.add_liquidity(deposit_amounts, size * INITIAL_AMOUNT // 2 * 10**18 * 101 // 100, sender=bob) + + +def test_event(bob, swap, pool_type, deposit_amounts, pool_tokens, pool_token_types, metapool_token_type): + size = 2 + check_invariant = True + if pool_type == 0: + size = len(pool_tokens) + + for t in pool_token_types: + if t != 0: + check_invariant = False + + if pool_type == 1: + if metapool_token_type != 0: + check_invariant = False + + _, events = call_returning_result_and_logs(swap, "add_liquidity", deposit_amounts, 0, sender=bob) + + assert len(events) == 4 # Transfer token1, Transfer token2, Transfer LP, Add liquidity + if check_invariant: + assert ( + repr(events[3]) == f"AddLiquidity(provider={bob}, token_amounts={deposit_amounts}, fees=[0, 0], " + f"invariant={size * INITIAL_AMOUNT * 10 ** 18}, token_supply={swap.totalSupply()})" + ) + + +def test_send_eth(bob, swap, deposit_amounts): + with boa.reverts(): + swap.add_liquidity(deposit_amounts, 0, sender=bob, value=1) diff --git a/tests/pools/liquidity/test_initial_liquidity.py b/tests/pools/liquidity/test_initial_liquidity.py new file mode 100644 index 00000000..cf48a36e --- /dev/null +++ b/tests/pools/liquidity/test_initial_liquidity.py @@ -0,0 +1,68 @@ +import boa +import pytest + +from tests.fixtures.accounts import add_base_pool_liquidity, mint_account +from tests.utils.tokens import mint_for_testing + + +@pytest.fixture() +def initial_setup_alice( + alice, + deposit_amounts, + swap, + pool_type, + base_pool, + base_pool_tokens, + base_pool_decimals, + base_pool_lp_token, + initial_balance, + initial_amounts, + pool_tokens, + underlying_tokens, +): + mint_for_testing(alice, 1 * 10**18, None, True) + + if pool_type == 0: + mint_account(alice, pool_tokens, initial_balance, initial_amounts) + with boa.env.prank(alice): + for token in pool_tokens: + token.approve(swap.address, 2**256 - 1) + + else: + add_base_pool_liquidity(alice, base_pool, base_pool_tokens, base_pool_decimals) + mint_for_testing(alice, initial_amounts[0], underlying_tokens[0], False) + + with boa.env.prank(alice): + for token in underlying_tokens: + token.approve(swap.address, 2**256 - 1) + + +@pytest.mark.parametrize("min_amount", [0, 10**18]) +def test_initial( + alice, + initial_setup_alice, + swap, + pool_type, + pool_tokens, + underlying_tokens, + pool_token_types, + metapool_token_type, + min_amount, + decimals, + meta_decimals, + deposit_amounts, + initial_amounts, +): + swap.add_liquidity(deposit_amounts, len(pool_tokens) * min_amount, sender=alice) + + token_types = pool_token_types if pool_type == 0 else [metapool_token_type, 18] + + for coin, und_coin, amount, initial, pool_token_type in zip( + pool_tokens, underlying_tokens, deposit_amounts, initial_amounts, token_types + ): + if pool_type == 0: + assert coin.balanceOf(alice) == pytest.approx(initial - amount, rel=1.5e-2) + assert coin.balanceOf(swap) == pytest.approx(amount, rel=1.5e-2) + else: + assert und_coin.balanceOf(alice) == pytest.approx(initial - amount, rel=1.5e-2) + assert und_coin.balanceOf(swap) == pytest.approx(amount, rel=1.5e-2) diff --git a/tests/pools/liquidity/test_remove_liquidity.py b/tests/pools/liquidity/test_remove_liquidity.py new file mode 100644 index 00000000..4c67a70b --- /dev/null +++ b/tests/pools/liquidity/test_remove_liquidity.py @@ -0,0 +1,54 @@ +import boa +import pytest + +from tests.utils.transactions import call_returning_result_and_logs + +pytestmark = pytest.mark.usefixtures("initial_setup") + + +@pytest.mark.parametrize("min_amount", (0, 1)) +def test_remove_liquidity(alice, swap, pool_type, pool_tokens, underlying_tokens, min_amount, deposit_amounts): + swap.remove_liquidity(swap.balanceOf(alice), [i * min_amount for i in deposit_amounts], sender=alice) + + coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] + + for coin, amount in zip(coins, deposit_amounts): + assert coin.balanceOf(alice) == pytest.approx(amount * 2, rel=1.5e-2) + assert coin.balanceOf(swap) == 0 + + assert swap.balanceOf(alice) == 0 + assert swap.totalSupply() == 0 + + +def test_remove_partial(alice, swap, pool_type, pool_tokens, underlying_tokens, pool_size): + initial_amount = swap.balanceOf(alice) + withdraw_amount = initial_amount // 2 + coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] + swap.remove_liquidity(withdraw_amount, [0] * pool_size, sender=alice) + + for coin in coins: + assert coin.balanceOf(swap) + coin.balanceOf(alice) == pytest.approx(initial_amount, rel=1.5e-2) + + assert swap.balanceOf(alice) == initial_amount - withdraw_amount + assert swap.totalSupply() == initial_amount - withdraw_amount + + +@pytest.mark.parametrize("idx", range(2)) +def test_below_min_amount(alice, swap, initial_amounts, idx): + min_amount = initial_amounts.copy() + min_amount[idx] += 1 + + with boa.reverts(): + swap.remove_liquidity(swap.balanceOf(alice), min_amount, sender=alice) + + +def test_amount_exceeds_balance(alice, swap, pool_size): + with boa.reverts(): + swap.remove_liquidity(swap.balanceOf(alice) + 1, [0] * pool_size, sender=alice) + + +def test_event(alice, bob, swap, pool_size): + swap.transfer(bob, 10**18, sender=alice) + _, events = call_returning_result_and_logs(swap, "remove_liquidity", 10**18, [0] * pool_size, sender=alice) + + assert f"RemoveLiquidity(provider={alice}" in repr(events[3]) diff --git a/tests/pools/liquidity/test_remove_liquidity_imbalance.py b/tests/pools/liquidity/test_remove_liquidity_imbalance.py new file mode 100644 index 00000000..2cb5fad6 --- /dev/null +++ b/tests/pools/liquidity/test_remove_liquidity_imbalance.py @@ -0,0 +1,78 @@ +import boa +import pytest + +from tests.utils.transactions import call_returning_result_and_logs + +pytestmark = pytest.mark.usefixtures("initial_setup") + + +@pytest.mark.parametrize("divisor", [2, 5, 10]) +def test_remove_balanced( + alice, swap, pool_type, pool_tokens, underlying_tokens, divisor, deposit_amounts, initial_amounts +): + initial_balance = swap.balanceOf(alice) + amounts = [i // divisor for i in deposit_amounts] + swap.remove_liquidity_imbalance(amounts, initial_balance, sender=alice) + + coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] + + for i, coin in enumerate(coins): + assert coin.balanceOf(alice) == pytest.approx(amounts[i] + initial_amounts[i] - deposit_amounts[i], rel=1.5e-2) + assert coin.balanceOf(swap) == pytest.approx(deposit_amounts[i] - amounts[i], rel=1.5e-2) + + assert swap.balanceOf(alice) / initial_balance == pytest.approx(1 - 1 / divisor, rel=1.5e-2) + + +@pytest.mark.parametrize("idx", range(2)) +def test_remove_one( + alice, swap, pool_type, pool_tokens, underlying_tokens, pool_size, idx, deposit_amounts, initial_amounts +): + amounts = [0] * pool_size + amounts[idx] = deposit_amounts[idx] // 2 + + lp_balance = pool_size * deposit_amounts[idx] + swap.remove_liquidity_imbalance(amounts, lp_balance, sender=alice) + + coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] + + for i, coin in enumerate(coins): + assert coin.balanceOf(alice) == pytest.approx(amounts[i] + initial_amounts[i] - deposit_amounts[i], rel=1.5e-2) + assert coin.balanceOf(swap) == pytest.approx(deposit_amounts[i] - amounts[i], rel=1.5e-2) + + actual_balance = swap.balanceOf(alice) + actual_total_supply = swap.totalSupply() + ideal_balance = (2 * pool_size - 1) * lp_balance / (2 * pool_size) + + assert actual_balance == actual_total_supply + assert ideal_balance * 0.9994 < actual_balance + assert actual_balance < ideal_balance * 1.07 + + +@pytest.mark.parametrize("divisor", [1, 2, 10]) +def test_exceed_max_burn(alice, swap, pool_size, divisor, deposit_amounts): + amounts = [i // divisor for i in deposit_amounts] + max_burn = pool_size * 1_000_000 * 10**18 // divisor + + with boa.reverts(): + swap.remove_liquidity_imbalance(amounts, max_burn - 1, sender=alice) + + +def test_cannot_remove_zero(alice, swap, pool_size): + with boa.reverts(): + swap.remove_liquidity_imbalance([0] * pool_size, 0, sender=alice) + + +def test_no_total_supply(alice, swap, pool_size): + swap.remove_liquidity(swap.totalSupply(), [0] * pool_size, sender=alice) + with boa.reverts(): + swap.remove_liquidity_imbalance([0] * pool_size, 0, sender=alice) + + +def test_event(alice, bob, swap, pool_size, deposit_amounts): + swap.transfer(bob, swap.balanceOf(alice), sender=alice) + amounts = [i // 5 for i in deposit_amounts] + max_burn = pool_size * 1_000_000 * 10**18 + + _, events = call_returning_result_and_logs(swap, "remove_liquidity_imbalance", amounts, max_burn, sender=bob) + + assert f"RemoveLiquidityImbalance(provider={bob}" in repr(events[3]) diff --git a/tests/pools/liquidity/test_remove_liquidity_one_coin.py b/tests/pools/liquidity/test_remove_liquidity_one_coin.py new file mode 100644 index 00000000..d5fb565b --- /dev/null +++ b/tests/pools/liquidity/test_remove_liquidity_one_coin.py @@ -0,0 +1,74 @@ +import boa +import pytest + +from tests.utils.transactions import call_returning_result_and_logs + +pytestmark = pytest.mark.usefixtures("initial_setup") + + +@pytest.mark.parametrize("idx", range(2)) +def test_amount_received(alice, swap, pool_type, pool_tokens, underlying_tokens, decimals, idx): + coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] + initial_amount = coins[idx].balanceOf(alice) + + swap.remove_liquidity_one_coin(10**18, idx, 0, sender=alice) + ideal = 10 ** decimals[idx] + assert ideal * 0.99 <= coins[idx].balanceOf(alice) - initial_amount <= ideal + + +@pytest.mark.parametrize("idx", range(2)) +@pytest.mark.parametrize("divisor", [1, 5, 42]) +def test_lp_token_balance(alice, swap, idx, divisor): + initial_amount = swap.balanceOf(alice) + amount = initial_amount // divisor + + if divisor == 1: + with boa.reverts(): + swap.remove_liquidity_one_coin(amount, idx, 0, sender=alice) + else: + swap.remove_liquidity_one_coin(amount, idx, 0, sender=alice) + + assert swap.balanceOf(alice) + amount == initial_amount + + +@pytest.mark.parametrize("idx", range(2)) +def test_expected_vs_actual(alice, swap, pool_type, pool_tokens, underlying_tokens, idx): + coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] + initial_amount = coins[idx].balanceOf(alice) + amount = swap.balanceOf(alice) // 10 + + expected = swap.calc_withdraw_one_coin(amount, idx) + swap.remove_liquidity_one_coin(amount, idx, 0, sender=alice) + assert coins[idx].balanceOf(alice) == expected + initial_amount + + +@pytest.mark.parametrize("idx", range(2)) +def test_below_min_amount(alice, swap, idx): + amount = swap.balanceOf(alice) + + expected = swap.calc_withdraw_one_coin(amount, idx) + with boa.reverts(): + swap.remove_liquidity_one_coin(amount, idx, expected + 1, sender=alice) + + +@pytest.mark.parametrize("idx", range(2)) +def test_amount_exceeds_balance(bob, swap, idx): + with boa.reverts(): + swap.remove_liquidity_one_coin(1, idx, 0, sender=bob) + + +def test_below_zero(alice, swap): + with boa.reverts(): + swap.remove_liquidity_one_coin(1, -1, 0, sender=alice) + + +def test_above_n_coins(alice, swap, pool_size): + with boa.reverts(): + swap.remove_liquidity_one_coin(1, pool_size, 0, sender=alice) + + +@pytest.mark.parametrize("idx", range(2)) +def test_event(alice, bob, swap, idx): + swap.transfer(bob, 10**18, sender=alice) + _, events = call_returning_result_and_logs(swap, "remove_liquidity_one_coin", 10**18, idx, 0, sender=bob) + assert f"RemoveLiquidityOne(provider={bob}" in repr(events[2]) diff --git a/tests/pools/meta/__init__.py b/tests/pools/meta/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/pools/meta/test_exchange_underlying.py b/tests/pools/meta/test_exchange_underlying.py index 64c84f19..7b7ec435 100644 --- a/tests/pools/meta/test_exchange_underlying.py +++ b/tests/pools/meta/test_exchange_underlying.py @@ -4,15 +4,14 @@ from tests.utils import approx -pytestmark = pytest.mark.usefixtures("initial_setup") +pytestmark = pytest.mark.usefixtures("meta_setup") +permutations = list(itertools.permutations(range(4), 2)) # 0,1...3,2 -@pytest.mark.only_for_pool_type(1) # only for metapools -@pytest.mark.skip_oracle_tokens -@pytest.mark.skip_rebasing_tokens -@pytest.mark.parametrize("sending,receiving", filter(lambda k: 0 in k, itertools.permutations(range(4), 2))) -def test_amounts(bob, swap, underlying_tokens, sending, receiving, meta_decimals, base_pool_decimals): +@pytest.mark.only_plain_tokens +@pytest.mark.parametrize("sending,receiving", [p for p in permutations if 0 in p]) +def test_amounts(bob, meta_swap, underlying_tokens, sending, receiving, meta_decimals, base_pool_decimals): underlying_decimals = [meta_decimals] + base_pool_decimals underlying_tokens = [underlying_tokens[0], *underlying_tokens[2:]] amount_sent = 10 ** underlying_decimals[sending] @@ -20,22 +19,20 @@ def test_amounts(bob, swap, underlying_tokens, sending, receiving, meta_decimals if sending > 0 and underlying_tokens[sending].balanceOf(bob) < amount_sent: underlying_tokens[sending]._mint_for_testing(bob, amount_sent) - expected_received = swap.get_dy_underlying(sending, receiving, amount_sent) - received_true = swap.exchange_underlying(sending, receiving, amount_sent, 0, sender=bob) # noqa: F841 + expected_received = meta_swap.get_dy_underlying(sending, receiving, amount_sent) + received_true = meta_swap.exchange_underlying(sending, receiving, amount_sent, 0, sender=bob) # noqa: F841 assert approx(received_true, expected_received, 1e-3) -@pytest.mark.only_for_pool_type(1) # only for metapools -@pytest.mark.skip_rebasing_tokens -@pytest.mark.skip_oracle_tokens -@pytest.mark.parametrize("sending,receiving", itertools.permutations(range(4), 2)) -def test_min_dy_underlying(bob, swap, underlying_tokens, sending, receiving, meta_decimals, base_pool_decimals): +@pytest.mark.only_plain_tokens +@pytest.mark.parametrize("sending,receiving", permutations) +def test_min_dy_underlying(bob, meta_swap, underlying_tokens, sending, receiving, meta_decimals, base_pool_decimals): underlying_decimals = [meta_decimals] + base_pool_decimals underlying_tokens = [underlying_tokens[0], *underlying_tokens[2:]] amount = 10 ** underlying_decimals[sending] underlying_tokens[sending]._mint_for_testing(bob, amount, sender=bob) - expected = swap.get_dy_underlying(sending, receiving, amount) - received = swap.exchange_underlying(sending, receiving, amount, 0, sender=bob) + expected = meta_swap.get_dy_underlying(sending, receiving, amount) + received = meta_swap.exchange_underlying(sending, receiving, amount, 0, sender=bob) assert approx(expected, received, 1e-3) diff --git a/tests/pools/meta/test_exchange_underlying_reverts.py b/tests/pools/meta/test_exchange_underlying_reverts.py index 41175ba2..078e232d 100644 --- a/tests/pools/meta/test_exchange_underlying_reverts.py +++ b/tests/pools/meta/test_exchange_underlying_reverts.py @@ -3,57 +3,70 @@ import boa import pytest -pytestmark = pytest.mark.usefixtures("initial_setup") - - -@pytest.mark.only_for_pool_type(1) # only for metapools -class TestMetaExchangeUnderlyingReverts: - @pytest.mark.parametrize("sending,receiving", itertools.permutations(range(4), 2)) - def test_min_dy_too_high(self, bob, swap, underlying_tokens, meta_decimals, base_pool_decimals, sending, receiving): - underlying_decimals = [meta_decimals] + base_pool_decimals - underlying_tokens = [underlying_tokens[0], *underlying_tokens[2:]] - amount = 10 ** underlying_decimals[sending] - underlying_tokens[sending]._mint_for_testing(bob, amount, sender=bob) - - min_dy = swap.get_dy_underlying(sending, receiving, int(amount * 1.0001)) - with boa.reverts(): - swap.exchange_underlying(sending, receiving, amount, min_dy, sender=bob) - - @pytest.mark.parametrize("sending,receiving", itertools.permutations(range(4), 2)) - def test_insufficient_balance( - self, bob, swap, underlying_tokens, meta_decimals, base_pool_decimals, sending, receiving, zero_address - ): - underlying_decimals = [meta_decimals] + base_pool_decimals - underlying_tokens = [underlying_tokens[0], *underlying_tokens[2:]] - amount = 10 ** underlying_decimals[sending] - underlying_tokens[sending]._mint_for_testing(bob, amount, sender=bob) - underlying_tokens[sending].transfer(zero_address, underlying_tokens[sending].balanceOf(bob), sender=bob) - - underlying_tokens[sending]._mint_for_testing(bob, amount, sender=bob) - with boa.reverts(): - swap.exchange_underlying(sending, receiving, amount + 1, 0, sender=bob) - - @pytest.mark.parametrize("idx", range(4)) - def test_same_coin(self, bob, swap, idx): - with boa.reverts(): - swap.exchange_underlying(idx, idx, 0, 0, sender=bob) - - @pytest.mark.parametrize("idx", [-1, -(2**127)]) - def test_i_below_zero(self, bob, swap, idx): - with boa.reverts(): - swap.exchange_underlying(idx, 0, 0, 0, sender=bob) - - @pytest.mark.parametrize("idx", [4, 2**127 - 1]) - def test_i_above_n_coins(self, bob, swap, idx): - with boa.reverts(): - swap.exchange_underlying(idx, 0, 0, 0, sender=bob) - - @pytest.mark.parametrize("idx", [-1, -(2**127)]) - def test_j_below_zero(self, bob, swap, idx): - with boa.reverts(): - swap.exchange_underlying(0, idx, 0, 0, sender=bob) - - @pytest.mark.parametrize("idx", [4, 2**127 - 1]) - def test_j_above_n_coins(self, bob, swap, idx): - with boa.reverts(): - swap.exchange_underlying(0, idx, 0, 0, sender=bob) +from tests.constants import TOKEN_TYPES + +pytestmark = pytest.mark.usefixtures("meta_setup") + +permutations = list(itertools.permutations(range(4), 2)) # 0,1...3,2 + + +@pytest.mark.parametrize("sending,receiving", permutations) +def test_min_dy_too_high( + bob, meta_swap, underlying_tokens, meta_decimals, base_pool_decimals, sending, receiving, metapool_token_type +): + if sending == 0 and metapool_token_type == TOKEN_TYPES["rebasing"]: + return pytest.skip("This test does not revert sending rebasing tokens") # TODO + + underlying_decimals = [meta_decimals] + base_pool_decimals + underlying_tokens = [underlying_tokens[0], *underlying_tokens[2:]] + amount = 10 ** underlying_decimals[sending] + underlying_tokens[sending]._mint_for_testing(bob, amount, sender=bob) + + min_dy = meta_swap.get_dy_underlying(sending, receiving, int(amount * 1.0001)) + with boa.reverts(): + meta_swap.exchange_underlying(sending, receiving, amount, min_dy, sender=bob) + + +@pytest.mark.parametrize("sending,receiving", permutations) +def test_insufficient_balance( + bob, meta_swap, underlying_tokens, meta_decimals, base_pool_decimals, sending, receiving, zero_address +): + underlying_decimals = [meta_decimals] + base_pool_decimals + underlying_tokens = [underlying_tokens[0], *underlying_tokens[2:]] + amount = 10 ** underlying_decimals[sending] + underlying_tokens[sending]._mint_for_testing(bob, amount, sender=bob) + underlying_tokens[sending].transfer(zero_address, underlying_tokens[sending].balanceOf(bob), sender=bob) + + underlying_tokens[sending]._mint_for_testing(bob, amount, sender=bob) + with boa.reverts(): + meta_swap.exchange_underlying(sending, receiving, amount + 1, 0, sender=bob) + + +@pytest.mark.parametrize("idx", range(4)) +def test_same_coin(bob, meta_swap, idx): + with boa.reverts(): + meta_swap.exchange_underlying(idx, idx, 0, 0, sender=bob) + + +@pytest.mark.parametrize("idx", [-1, -(2**127)]) +def test_i_below_zero(bob, meta_swap, idx): + with boa.reverts(): + meta_swap.exchange_underlying(idx, 0, 0, 0, sender=bob) + + +@pytest.mark.parametrize("idx", [4, 2**127 - 1]) +def test_i_above_n_coins(bob, meta_swap, idx): + with boa.reverts(): + meta_swap.exchange_underlying(idx, 0, 0, 0, sender=bob) + + +@pytest.mark.parametrize("idx", [-1, -(2**127)]) +def test_j_below_zero(bob, meta_swap, idx): + with boa.reverts(): + meta_swap.exchange_underlying(0, idx, 0, 0, sender=bob) + + +@pytest.mark.parametrize("idx", [4, 2**127 - 1]) +def test_j_above_n_coins(bob, meta_swap, idx): + with boa.reverts(): + meta_swap.exchange_underlying(0, idx, 0, 0, sender=bob) diff --git a/tests/pools/meta/test_get_virtual_price_meta.py b/tests/pools/meta/test_get_virtual_price_meta.py index 4349c241..7360cc17 100644 --- a/tests/pools/meta/test_get_virtual_price_meta.py +++ b/tests/pools/meta/test_get_virtual_price_meta.py @@ -2,18 +2,18 @@ import pytest -pytestmark = pytest.mark.usefixtures("initial_setup") +pytestmark = pytest.mark.usefixtures("meta_setup") @pytest.mark.parametrize("sending,receiving", itertools.permutations(range(4), 2)) -def test_exchange_underlying(bob, swap, sending, receiving, meta_decimals, base_pool_decimals, underlying_tokens): +def test_exchange_underlying(bob, meta_swap, sending, receiving, meta_decimals, base_pool_decimals, underlying_tokens): underlying_decimals = [meta_decimals] + base_pool_decimals - virtual_price = swap.get_virtual_price() + virtual_price = meta_swap.get_virtual_price() amount = 10 ** underlying_decimals[sending] if sending > 0: underlying_tokens[sending + 1]._mint_for_testing(bob, amount) - swap.exchange_underlying(sending, receiving, amount, 0, sender=bob) + meta_swap.exchange_underlying(sending, receiving, amount, 0, sender=bob) - assert swap.get_virtual_price() > virtual_price + assert meta_swap.get_virtual_price() > virtual_price diff --git a/tests/pools/meta/test_meta_new_ng_base.py b/tests/pools/meta/test_meta_new_ng_base.py index 778d3ce5..cfabc129 100644 --- a/tests/pools/meta/test_meta_new_ng_base.py +++ b/tests/pools/meta/test_meta_new_ng_base.py @@ -13,34 +13,18 @@ def ng_base_pool_decimals(): return [18] * BASE_N_COINS -@pytest.fixture(scope="module") -def ng_base_pool_tokens(ng_base_pool_decimals): - tokens = [] - for i in range(BASE_N_COINS): - tokens.append(boa.load("contracts/mocks/ERC20.vy", f"tkn{i}", f"tkn{i}", ng_base_pool_decimals[i])) - - return tokens +@pytest.fixture() +def ng_base_pool_tokens(ng_base_pool_decimals, erc20_deployer): + return [erc20_deployer.deploy(f"tkn{i}", f"tkn{i}", ng_base_pool_decimals[i]) for i in range(BASE_N_COINS)] -@pytest.fixture(scope="module") -def meta_token(): - return boa.load( - "contracts/mocks/ERC20.vy", - "OTA", - "OTA", - 18, - ) +@pytest.fixture() +def meta_token(erc20_deployer): + return erc20_deployer.deploy("OTA", "OTA", 18) -@pytest.fixture(scope="module") -def ng_base_pool( - deployer, - factory, - ng_base_pool_tokens, - zero_address, - amm_interface, - set_pool_implementations, -): +@pytest.fixture() +def ng_base_pool(deployer, factory, ng_base_pool_tokens, zero_address, amm_deployer, set_pool_implementations): pool_size = len(ng_base_pool_tokens) offpeg_fee_multiplier = 20000000000 method_ids = [bytes(b"")] * pool_size @@ -63,38 +47,30 @@ def ng_base_pool( oracles, ) - return amm_interface.at(pool) + return amm_deployer.at(pool) -@pytest.fixture(scope="module") +@pytest.fixture() def ng_metapool_tokens(meta_token, ng_base_pool): return [meta_token, ng_base_pool] -@pytest.fixture(scope="module") -def add_ng_base_pool( - owner, - factory, - ng_base_pool, - ng_base_pool_tokens, -): +@pytest.fixture() +def add_ng_base_pool(owner, factory, ng_base_pool, ng_base_pool_tokens): with boa.env.prank(owner): factory.add_base_pool( - ng_base_pool.address, - ng_base_pool.address, - [0] * len(ng_base_pool_tokens), - len(ng_base_pool_tokens), + ng_base_pool.address, ng_base_pool.address, [0] * len(ng_base_pool_tokens), len(ng_base_pool_tokens) ) -@pytest.fixture(scope="module") +@pytest.fixture() def empty_swap( deployer, factory, zero_address, meta_token, ng_base_pool, - amm_interface_meta, + meta_deployer, add_ng_base_pool, set_metapool_implementations, ): @@ -120,10 +96,10 @@ def empty_swap( oracle, # _oracle: address ) - return amm_interface_meta.at(pool) + return meta_deployer.at(pool) -@pytest.fixture(scope="module") +@pytest.fixture() def mint_and_approve_for_bob(meta_token, ng_base_pool_tokens, bob, empty_swap, ng_base_pool): for token in [meta_token] + ng_base_pool_tokens: mint_for_testing(bob, 10**25, token) @@ -131,15 +107,9 @@ def mint_and_approve_for_bob(meta_token, ng_base_pool_tokens, bob, empty_swap, n token.approve(ng_base_pool, 2**256 - 1, sender=bob) -@pytest.fixture(scope="module") +@pytest.fixture() def deposit_amounts( - meta_token, - ng_base_pool, - ng_base_pool_tokens, - ng_base_pool_decimals, - empty_swap, - bob, - mint_and_approve_for_bob, + meta_token, ng_base_pool, ng_base_pool_tokens, ng_base_pool_decimals, empty_swap, bob, mint_and_approve_for_bob ): _deposit_amounts = [] INITIAL_AMOUNT = 1_000_000 * BASE_N_COINS @@ -157,19 +127,14 @@ def add_base_pool_liquidity(user, base_pool, base_pool_tokens, base_pool_decimal return _deposit_amounts -@pytest.fixture(scope="module") +@pytest.fixture() def swap(empty_swap, bob, deposit_amounts): empty_swap.add_liquidity(deposit_amounts, 0, bob, sender=bob) return empty_swap @pytest.mark.parametrize("sending,receiving", itertools.permutations(range(4), 2)) -def test_exchange_underlying_ng_base( - swap, - bob, - sending, - receiving, -): +def test_exchange_underlying_ng_base(swap, bob, sending, receiving): amount = 10**19 expected_out = swap.get_dy_underlying(sending, receiving, amount) actual_out = swap.exchange_underlying(sending, receiving, amount, 0, sender=bob) diff --git a/tests/pools/meta/test_meta_zap.py b/tests/pools/meta/test_meta_zap.py index 2735b10d..b713fdf9 100644 --- a/tests/pools/meta/test_meta_zap.py +++ b/tests/pools/meta/test_meta_zap.py @@ -8,54 +8,33 @@ warnings.filterwarnings("ignore") -@pytest.fixture(scope="module") -def meta_token(deployer): +@pytest.fixture() +def meta_token(deployer, erc20_deployer): with boa.env.prank(deployer): - return boa.load( - "contracts/mocks/ERC20.vy", - "OTA", - "OTA", - 18, - ) + return erc20_deployer.deploy("OTA", "OTA", 18) -@pytest.fixture(scope="module") +@pytest.fixture() def metapool_tokens(meta_token, base_pool): return [meta_token, base_pool] -@pytest.fixture(scope="module") +@pytest.fixture() def tokens_all(meta_token, base_pool_tokens): return [meta_token] + base_pool_tokens -@pytest.fixture(scope="module") -def add_base_pool( - owner, - factory, - base_pool, - base_pool_lp_token, - base_pool_tokens, -): +@pytest.fixture() +def add_base_pool(owner, factory, base_pool, base_pool_lp_token, base_pool_tokens): with boa.env.prank(owner): factory.add_base_pool( - base_pool.address, - base_pool_lp_token.address, - [0] * len(base_pool_tokens), - len(base_pool_tokens), + base_pool.address, base_pool_lp_token.address, [0] * len(base_pool_tokens), len(base_pool_tokens) ) -@pytest.fixture(scope="module") +@pytest.fixture() def empty_swap( - deployer, - factory, - zero_address, - meta_token, - base_pool, - amm_interface_meta, - add_base_pool, - set_metapool_implementations, + deployer, factory, zero_address, meta_token, base_pool, meta_deployer, add_base_pool, set_metapool_implementations ): method_id = bytes(b"") oracle = zero_address @@ -80,24 +59,21 @@ def empty_swap( oracle, # _oracle: address ) - return amm_interface_meta.at(pool) + return meta_deployer.at(pool) -@pytest.fixture(scope="module") -def zap(base_pool, base_pool_tokens, base_pool_lp_token): - return boa.load( - "contracts/mocks/Zap.vy", base_pool.address, base_pool_lp_token.address, [a.address for a in base_pool_tokens] - ) +@pytest.fixture() +def zap(base_pool, base_pool_tokens, base_pool_lp_token, zap_deployer): + return zap_deployer.deploy(base_pool.address, base_pool_lp_token.address, [a.address for a in base_pool_tokens]) -@pytest.fixture(scope="module") +@pytest.fixture() def initial_amts(): return [100 * 10**18] * 4 -@pytest.fixture(scope="module") +@pytest.fixture() def swap(zap, base_pool, empty_swap, charlie, tokens_all, initial_amts): - for i in range(3): assert base_pool.balances(i) == 0 @@ -114,7 +90,6 @@ def swap(zap, base_pool, empty_swap, charlie, tokens_all, initial_amts): def test_calc_amts_add(zap, swap, charlie, tokens_all): - deposit_amount = 2 * 100 * 10**18 for token in tokens_all: @@ -132,7 +107,6 @@ def test_calc_amts_add(zap, swap, charlie, tokens_all): def test_calc_amts_remove_imbalance( zap, swap, meta_token, base_pool_tokens, base_pool_lp_token, base_pool, charlie, tokens_all, initial_amts ): - amounts = [i // 4 for i in initial_amts] initial_balance = swap.balanceOf(charlie) swap.approve(zap, 2**256 - 1, sender=charlie) @@ -152,7 +126,6 @@ def test_calc_amts_remove_imbalance( def test_calc_amts_remove(zap, swap, charlie, tokens_all, meta_token, base_pool, base_pool_tokens): - charlie_bal_before = [] for _t in tokens_all: charlie_bal_before.append(_t.balanceOf(charlie)) diff --git a/tests/pools/meta/test_meta_zap_ng_base.py b/tests/pools/meta/test_meta_zap_ng_base.py new file mode 100644 index 00000000..0fe120c7 --- /dev/null +++ b/tests/pools/meta/test_meta_zap_ng_base.py @@ -0,0 +1,241 @@ +import warnings + +import boa +import pytest + +from tests.utils.tokens import mint_for_testing + +warnings.filterwarnings("ignore") + + +BASE_N_COINS = 5 + + +@pytest.fixture(scope="module") +def ng_base_pool_decimals(): + return [18] * BASE_N_COINS + + +@pytest.fixture() +def ng_base_pool_tokens(ng_base_pool_decimals, erc20_deployer): + return [erc20_deployer.deploy(f"tkn{i}", f"tkn{i}", ng_base_pool_decimals[i]) for i in range(BASE_N_COINS)] + + +@pytest.fixture() +def meta_token(erc20_deployer): + return erc20_deployer.deploy("OTA", "OTA", 18) + + +@pytest.fixture() +def tokens_all(meta_token, ng_base_pool_tokens): + return [meta_token] + ng_base_pool_tokens + + +@pytest.fixture() +def ng_base_pool(deployer, factory, ng_base_pool_tokens, zero_address, amm_deployer, set_pool_implementations, alice): + pool_size = len(ng_base_pool_tokens) + offpeg_fee_multiplier = 20000000000 + method_ids = [bytes(b"")] * pool_size + oracles = [zero_address] * pool_size + A = 1000 + fee = 3000000 + + with boa.env.prank(deployer): + pool = factory.deploy_plain_pool( + "test", + "test", + [t.address for t in ng_base_pool_tokens], + A, + fee, + offpeg_fee_multiplier, + 866, + 0, + [tkn.asset_type() for tkn in ng_base_pool_tokens], + method_ids, + oracles, + ) + + base_pool = amm_deployer.at(pool) + + amt_to_deposit = 10**18 + + for token in ng_base_pool_tokens: + mint_for_testing(alice, amt_to_deposit, token, False) + token.approve(base_pool.address, 2**256 - 1, sender=alice) + + out_amount = base_pool.add_liquidity([amt_to_deposit] * len(ng_base_pool_tokens), 0, sender=alice) + assert base_pool.totalSupply() == out_amount + return base_pool + + +@pytest.fixture() +def ng_metapool_tokens(meta_token, ng_base_pool): + return [meta_token, ng_base_pool] + + +@pytest.fixture() +def add_ng_base_pool(owner, factory, ng_base_pool, ng_base_pool_tokens): + with boa.env.prank(owner): + factory.add_base_pool( + ng_base_pool.address, ng_base_pool.address, [0] * len(ng_base_pool_tokens), len(ng_base_pool_tokens) + ) + + +@pytest.fixture() +def empty_swap( + deployer, + factory, + zero_address, + meta_token, + ng_base_pool, + meta_deployer, + add_ng_base_pool, + set_metapool_implementations, +): + method_id = bytes(b"") + oracle = zero_address + offpeg_fee_multiplier = 20000000000 + asset_type = meta_token.asset_type() + A = 1000 + fee = 3000000 + + with boa.env.prank(deployer): + pool = factory.deploy_metapool( + ng_base_pool.address, # _base_pool: address + "test", # _name: String[32], + "test", # _symbol: String[10], + meta_token.address, # _coin: address, + A, # _A: uint256, + fee, # _fee: uint256, + offpeg_fee_multiplier, + 866, # _ma_exp_time: uint256, + 0, # _implementation_idx: uint256 + asset_type, # _asset_type: uint8 + method_id, # _method_id: bytes4 + oracle, # _oracle: address + ) + + return meta_deployer.at(pool) + + +@pytest.fixture() +def zap(meta_zap_ng_deployer): + return meta_zap_ng_deployer.deploy() + + +@pytest.fixture() +def swap(zap, empty_swap, charlie, tokens_all): + to_deposit = 10**18 + + for token in tokens_all: + mint_for_testing(charlie, to_deposit, token, False) + token.approve(zap.address, 2**256 - 1, sender=charlie) + + out_amount = zap.add_liquidity(empty_swap.address, [to_deposit] * len(tokens_all), 0, sender=charlie) + assert out_amount > 0 + assert 0 not in empty_swap.get_balances() + assert empty_swap.totalSupply() > 0 + + return empty_swap + + +def test_calc_amts_add(zap, swap, charlie, tokens_all, ng_base_pool): + deposit_amount = 10**18 + for token in tokens_all: + mint_for_testing(charlie, deposit_amount, token, False) + token.approve(zap.address, 2**256 - 1, sender=charlie) + + deposit_amounts = [deposit_amount] * len(tokens_all) + + calc_amt_zap = zap.calc_token_amount(swap.address, deposit_amounts, True) + out_amount = zap.add_liquidity(swap.address, deposit_amounts, 0, sender=charlie) + + assert calc_amt_zap == out_amount + + +def test_calc_amts_remove_imbalance(zap, swap, meta_token, ng_base_pool_tokens, ng_base_pool, charlie, tokens_all): + initial_balance = swap.balanceOf(charlie) + amounts_to_remove = [initial_balance // len(tokens_all)] * len(tokens_all) + + swap.approve(zap, 2**256 - 1, sender=charlie) + max_burn = swap.balanceOf(charlie) + zap.remove_liquidity_imbalance(swap, amounts_to_remove, max_burn, sender=charlie) + + # check if charlie received what was wanted: + for i, token in enumerate(tokens_all): + assert token.balanceOf(charlie) == amounts_to_remove[i] + + # bob is the only LP, total supply is affected in the same way as his balance + assert swap.balanceOf(charlie) < initial_balance + assert swap.balanceOf(charlie) >= initial_balance - max_burn + + assert swap.balanceOf(zap) == 0 + assert swap.balanceOf(charlie) == swap.totalSupply() + + +def test_calc_amts_remove(zap, swap, charlie, tokens_all, meta_token, ng_base_pool, ng_base_pool_tokens): + charlie_bal_before = [] + for _t in tokens_all: + charlie_bal_before.append(_t.balanceOf(charlie)) + + charlie_lp_bal_before = swap.balanceOf(charlie) + + with boa.env.anchor(): + amts_received = swap.remove_liquidity(charlie_lp_bal_before, [0, 0], sender=charlie) + base_amts_received = ng_base_pool.remove_liquidity( + amts_received[1], [0] * ng_base_pool.N_COINS(), sender=charlie + ) + total_expected_received = [amts_received[0]] + base_amts_received + + swap.approve(zap, 2**256 - 1, sender=charlie) + total_received_amount = zap.remove_liquidity( + swap.address, charlie_lp_bal_before, [0] * len(tokens_all), sender=charlie + ) + + # tokens owned by zap: + zap_balances = [] + for token in tokens_all: + zap_balances.append(token.balanceOf(zap)) + + charlie_bal_after = [] + for _t in tokens_all: + charlie_bal_after.append(_t.balanceOf(charlie)) + + for i in range(len(tokens_all)): + assert total_received_amount[i] == total_expected_received[i] + + +def test_calc_amts_remove_one_meta_coin(zap, swap, charlie, tokens_all, meta_token, ng_base_pool, ng_base_pool_tokens): + charlie_bal_before = [] + for _t in tokens_all: + charlie_bal_before.append(_t.balanceOf(charlie)) + + lp_to_remove = swap.balanceOf(charlie) // 10 + calc_amt_removed = zap.calc_withdraw_one_coin(swap.address, lp_to_remove, 0, sender=charlie) + swap.approve(zap, 2**256 - 1, sender=charlie) + + with boa.env.anchor(): + amts_received_swap = swap.remove_liquidity_one_coin(lp_to_remove, 0, 0, sender=charlie) + assert calc_amt_removed == amts_received_swap + + amts_received_zap = zap.remove_liquidity_one_coin(swap.address, lp_to_remove, 0, 0, sender=charlie) + + assert amts_received_zap == amts_received_swap + + +def test_calc_amts_remove_one_base_coin(zap, swap, charlie, tokens_all, meta_token, ng_base_pool, ng_base_pool_tokens): + charlie_bal_before = [] + for _t in tokens_all: + charlie_bal_before.append(_t.balanceOf(charlie)) + + lp_to_remove = swap.balanceOf(charlie) // 10 + calc_amt_removed = zap.calc_withdraw_one_coin(swap.address, lp_to_remove, 1, sender=charlie) + swap.approve(zap, 2**256 - 1, sender=charlie) + + with boa.env.anchor(): + amts_received_swap = swap.remove_liquidity_one_coin(lp_to_remove, 1, 0, sender=charlie) + amts_received_base = ng_base_pool.remove_liquidity_one_coin(amts_received_swap, 0, 0, sender=charlie) + assert calc_amt_removed == amts_received_base + + amts_received_zap = zap.remove_liquidity_one_coin(swap.address, lp_to_remove, 1, 0, sender=charlie) + assert amts_received_zap == amts_received_base diff --git a/tests/pools/oracle/__init__.py b/tests/pools/oracle/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/pools/oracle/test_oracle.py b/tests/pools/oracle/test_oracle.py index b6257905..c2f04997 100644 --- a/tests/pools/oracle/test_oracle.py +++ b/tests/pools/oracle/test_oracle.py @@ -1,129 +1,128 @@ import boa import pytest +from tests.constants import POOL_TYPES, TOKEN_TYPES from tests.fixtures.accounts import add_base_pool_liquidity, mint_account from tests.fixtures.constants import INITIAL_AMOUNT from tests.utils.tokens import mint_for_testing DEPOSIT_AMOUNT = INITIAL_AMOUNT // 100 - - -@pytest.mark.only_for_token_types(1) -class TestOracle: - class TestInitialLiquidity: - @pytest.fixture(scope="module") - def initial_setup_alice( - self, - alice, - deposit_amounts, - swap, - pool_type, - base_pool, - base_pool_tokens, - base_pool_decimals, - base_pool_lp_token, - initial_balance, - initial_amounts, - pool_tokens, - underlying_tokens, - ): - with boa.env.anchor(): - mint_for_testing(alice, 1 * 10**18, None, True) - - if pool_type == 0: - mint_account(alice, pool_tokens, initial_balance, initial_amounts) - with boa.env.prank(alice): - for token in pool_tokens: - token.approve(swap.address, 2**256 - 1) - - else: - add_base_pool_liquidity(alice, base_pool, base_pool_tokens, base_pool_decimals) - mint_for_testing(alice, initial_amounts[0], underlying_tokens[0], False) - - with boa.env.prank(alice): - for token in underlying_tokens: - token.approve(swap.address, 2**256 - 1) - - yield - - def test_initial_liquidity( - self, - alice, - initial_setup_alice, - swap, - pool_type, - pool_token_types, - metapool_token_type, - decimals, - meta_decimals, - pool_tokens, - metapool_token, - ): - amounts = [] - - if pool_type == 0: - for i, t in enumerate(pool_token_types): - if t != 1: - amounts.append(DEPOSIT_AMOUNT * 10 ** decimals[i]) - else: - amounts.append(DEPOSIT_AMOUNT * 10 ** decimals[i] * 10**18 // pool_tokens[i].exchangeRate()) - else: - if metapool_token_type == 1: - amounts = [ - DEPOSIT_AMOUNT * 10**meta_decimals * 10**18 // metapool_token.exchangeRate(), - DEPOSIT_AMOUNT * 10**18, - ] - else: - amounts = [DEPOSIT_AMOUNT * 10**meta_decimals, DEPOSIT_AMOUNT * 10**18] - - swap.add_liquidity(amounts, 0, sender=alice) - swap.add_liquidity(amounts, 0, sender=alice) - - assert swap.admin_balances(0) == 0 - assert swap.admin_balances(1) == 0 - - def test_oracles(self, alice, swap, pool_size, pool_type, pool_token_types, metapool_token_type): - assert swap._storage.oracles.get() != [0] * pool_size - - def test_get_dy( - self, - alice, - initial_setup_alice, - swap, - pool_type, - pool_token_types, - metapool_token_type, - decimals, - meta_decimals, - pool_tokens, - metapool_token, - ): - amounts = [] - - if pool_type == 0: - for i, t in enumerate(pool_token_types): - if t != 1: - amounts.append(DEPOSIT_AMOUNT * 10 ** decimals[i]) - else: - amounts.append(DEPOSIT_AMOUNT * 10 ** decimals[i] * 10**18 // pool_tokens[i].exchangeRate()) - else: - if metapool_token_type == 1: - amounts = [ - DEPOSIT_AMOUNT * 10**meta_decimals * 10**18 // metapool_token.exchangeRate(), - DEPOSIT_AMOUNT * 10**18, - ] - else: - amounts = [DEPOSIT_AMOUNT * 10**meta_decimals, DEPOSIT_AMOUNT * 10**18] - - swap.add_liquidity(amounts, 0, sender=alice) - - if pool_type == 0: - rate_1 = 10**18 if pool_token_types[0] != 1 else pool_tokens[0].exchangeRate() - rate_2 = 10**18 if pool_token_types[1] != 1 else pool_tokens[1].exchangeRate() - - assert swap.get_dy(0, 1, rate_2) == pytest.approx(rate_1, rel=1e-3) - - else: - rate_1 = 1 if metapool_token_type != 1 else metapool_token.exchangeRate() - - assert swap.get_dy(0, 1, 10**18) == pytest.approx(rate_1, rel=1e-3) +pytestmark = pytest.mark.only_oracle_tokens + + +@pytest.fixture() +def initial_setup_alice(pool_type, request): + """ + Set up the initial state for Alice. + Run either the basic or meta fixture depending on the pool type. + """ + fixtures = {POOL_TYPES["basic"]: "basic_setup_alice", POOL_TYPES["meta"]: "meta_setup_alice"} + return request.getfixturevalue(fixtures[pool_type]) + + +@pytest.fixture() +def basic_setup_alice( + alice, + initial_amounts, + initial_balance, + oracle_tokens, + basic_swap, + base_pool_tokens, + base_pool, + base_pool_decimals, + underlying_tokens, +): + mint_for_testing(alice, amount=1 * 10**18, token_contract=None, mint_eth=True) + mint_account(alice, oracle_tokens, initial_balance, initial_amounts) + with boa.env.prank(alice): + for token in oracle_tokens: + token.approve(basic_swap.address, 2**256 - 1) + + +@pytest.fixture() +def meta_setup_alice( + alice, base_pool_tokens, base_pool, base_pool_decimals, initial_amounts, meta_swap, underlying_tokens +): + mint_for_testing(alice, amount=1 * 10**18, token_contract=None, mint_eth=True) + add_base_pool_liquidity(alice, base_pool, base_pool_tokens, base_pool_decimals) + mint_for_testing(alice, initial_amounts[0], underlying_tokens[0], False) + with boa.env.prank(alice): + for token in underlying_tokens: + token.approve(meta_swap.address, 2**256 - 1) + + +def test_initial_liquidity( + alice, + initial_setup_alice, + swap, + pool_type, + pool_token_types, + metapool_token_type, + decimals, + meta_decimals, + oracle_tokens, + metapool_token, +): + if pool_type == 0: + amounts = [ + DEPOSIT_AMOUNT * 10 ** decimals[i] * 10**18 // oracle_tokens[i].exchangeRate() + if t == TOKEN_TYPES["oracle"] + else DEPOSIT_AMOUNT * 10 ** decimals[i] + for i, t in enumerate(pool_token_types) + ] + else: + amounts = ( + [ + DEPOSIT_AMOUNT * 10**meta_decimals * 10**18 // metapool_token.exchangeRate(), + DEPOSIT_AMOUNT * 10**18, + ] + if metapool_token_type == 1 + else [DEPOSIT_AMOUNT * 10**meta_decimals, DEPOSIT_AMOUNT * 10**18] + ) + + swap.add_liquidity(amounts, 0, sender=alice) + swap.add_liquidity(amounts, 0, sender=alice) + + assert swap.admin_balances(0) == 0 + assert swap.admin_balances(1) == 0 + + +def test_oracles(alice, swap, pool_size, pool_type): + if pool_type == POOL_TYPES["basic"]: + assert swap._immutables.rate_oracles != [0] * pool_size + else: + assert swap._immutables.rate_oracle + + +def test_get_dy_basic( + alice, initial_setup_alice, basic_swap, pool_token_types, decimals, meta_decimals, oracle_tokens, metapool_token +): + amounts = [ + DEPOSIT_AMOUNT * 10 ** decimals[i] * 10**18 // oracle_tokens[i].exchangeRate() + if t == 1 + else DEPOSIT_AMOUNT * 10 ** decimals[i] + for i, t in enumerate(pool_token_types) + ] + + basic_swap.add_liquidity(amounts, 0, sender=alice) + + rate_1 = 10**18 if pool_token_types[0] != 1 else oracle_tokens[0].exchangeRate() + rate_2 = 10**18 if pool_token_types[1] != 1 else oracle_tokens[1].exchangeRate() + + assert basic_swap.get_dy(0, 1, rate_2) == pytest.approx(rate_1, rel=1e-3) + + +def test_get_dy_meta( + alice, initial_setup_alice, meta_swap, metapool_token_type, decimals, meta_decimals, oracle_tokens, metapool_token +): + amounts = ( + [DEPOSIT_AMOUNT * 10**meta_decimals * 10**18 // metapool_token.exchangeRate(), DEPOSIT_AMOUNT * 10**18] + if metapool_token_type == 1 + else [DEPOSIT_AMOUNT * 10**meta_decimals, DEPOSIT_AMOUNT * 10**18] + ) + + meta_swap.add_liquidity(amounts, 0, sender=alice) + + rate_1 = 1 if metapool_token_type != 1 else metapool_token.exchangeRate() + + assert meta_swap.get_dy(0, 1, 10**18) == pytest.approx(rate_1, rel=1e-3) diff --git a/tests/pools/test_oracles.py b/tests/pools/oracle/test_oracles.py similarity index 88% rename from tests/pools/test_oracles.py rename to tests/pools/oracle/test_oracles.py index 9b732bb4..fb3abdea 100644 --- a/tests/pools/test_oracles.py +++ b/tests/pools/oracle/test_oracles.py @@ -4,17 +4,16 @@ import boa import pytest from boa.test import strategy -from hypothesis import given, settings +from hypothesis import HealthCheck, given, settings from tests.utils import approx from tests.utils.tokens import mint_for_testing -SETTINGS = {"max_examples": 1000, "deadline": None} +SETTINGS = {"max_examples": 100, "deadline": None, "suppress_health_check": [HealthCheck.function_scoped_fixture]} pytestmark = pytest.mark.usefixtures("initial_setup") def get_D(swap, math): - _rates = swap.stored_rates() _balances = swap.internal._balances() xp = swap.internal._xp_mem(_rates, _balances) @@ -25,8 +24,9 @@ def get_D(swap, math): def check_oracle(swap, dt): # amm prices: p_amm = [] - for n in range(swap.N_COINS() - 1): - + coins = swap.N_COINS() - 1 + assert 0 < coins < 10 + for n in range(coins): _p = swap.get_p(n) assert approx(swap.last_price(n), _p, 1e-5) @@ -41,18 +41,14 @@ def check_oracle(swap, dt): w = exp(-dt / 866) # check: - for n in range(swap.N_COINS() - 1): - + for n in range(coins): p1 = int(10**18 * w + p_amm[n] * (1 - w)) assert approx(swap.price_oracle(n), p1, 1e-5) -@given( - amount=strategy("uint256", min_value=1, max_value=10**6), -) +@given(amount=strategy("uint256", min_value=1, max_value=10**6)) @settings(**SETTINGS) def test_get_p(swap, views_implementation, bob, pool_tokens, decimals, amount): - i, j = random.sample(range(swap.N_COINS()), 2) # calc amount in: @@ -69,7 +65,6 @@ def test_get_p(swap, views_implementation, bob, pool_tokens, decimals, amount): p_numeric = [] stored_rates = swap.stored_rates() for n in range(1, swap.N_COINS()): - expected_jth_out = views_implementation.get_dy(0, n, 10**18, swap) p_numeric.append(stored_rates[0] / expected_jth_out) @@ -90,7 +85,6 @@ def test_get_p(swap, views_implementation, bob, pool_tokens, decimals, amount): ) @settings(**SETTINGS) def test_price_ema_exchange(swap, bob, pool_tokens, underlying_tokens, decimals, amount, dt0, dt): - i, j = random.sample(range(swap.N_COINS()), 2) # calc amount in: @@ -112,8 +106,7 @@ def test_price_ema_exchange(swap, bob, pool_tokens, underlying_tokens, decimals, ) @settings(**SETTINGS) def test_price_ema_remove_one(swap, alice, amount, dt0, dt): - - i = random.sample(range(swap.N_COINS()), 1)[0] + i = random.choice(range(swap.N_COINS())) alice_lp_bal = swap.balanceOf(alice) amt_to_remove = int(alice_lp_bal * amount / (10**5 - 1)) @@ -130,8 +123,7 @@ def test_price_ema_remove_one(swap, alice, amount, dt0, dt): ) @settings(**SETTINGS) def test_price_ema_remove_imbalance(swap, alice, dt0, dt, pool_size, deposit_amounts, frac): - - i = random.sample(range(swap.N_COINS()), 1)[0] + i = random.choice(range(swap.N_COINS())) amounts = [0] * pool_size amounts[i] = deposit_amounts[i] // frac lp_balance = pool_size * deposit_amounts[i] @@ -142,13 +134,9 @@ def test_price_ema_remove_imbalance(swap, alice, dt0, dt, pool_size, deposit_amo check_oracle(swap, dt) -@given( - amount=strategy("uint256", min_value=10**9, max_value=10**15), -) +@given(amount=strategy("uint256", min_value=10**9, max_value=10**15)) @settings(**SETTINGS) -@pytest.mark.only_for_pool_type(0) -def test_manipulate_ema(swap, bob, pool_tokens, underlying_tokens, decimals, amount): - +def test_manipulate_ema(basic_swap, bob, pool_tokens, underlying_tokens, decimals, amount): # calc amount in: amount_in = amount * 10 ** (decimals[0]) @@ -158,7 +146,7 @@ def test_manipulate_ema(swap, bob, pool_tokens, underlying_tokens, decimals, amo # do large swap try: - swap.exchange(0, 1, amount_in, 0, sender=bob) + basic_swap.exchange(0, 1, amount_in, 0, sender=bob) except boa.BoaError: return # we're okay with failure to manipulate here @@ -166,7 +154,7 @@ def test_manipulate_ema(swap, bob, pool_tokens, underlying_tokens, decimals, amo boa.env.time_travel(blocks=500) # check if price oracle is way too high - p_oracle_after = swap.price_oracle(0) + p_oracle_after = basic_swap.price_oracle(0) assert p_oracle_after < 2 * 10**18 @@ -178,7 +166,6 @@ def test_manipulate_ema(swap, bob, pool_tokens, underlying_tokens, decimals, amo ) @settings(**SETTINGS) def test_D_ema(swap, bob, pool_tokens, underlying_tokens, decimals, amount, dt0, dt, math_implementation): - i, j = random.sample(range(swap.N_COINS()), 2) # calc amount in: diff --git a/tests/pools/test_donation_get_D.py b/tests/pools/test_donation_get_D.py deleted file mode 100644 index 1e700dde..00000000 --- a/tests/pools/test_donation_get_D.py +++ /dev/null @@ -1,34 +0,0 @@ -import boa -import pytest - -from tests.utils import get_asset_types_in_pool -from tests.utils.tokens import mint_for_testing - - -# @pytest.mark.skip_rebasing_tokens -@pytest.mark.only_for_pool_type(0) -def test_donate_get_D(bob, swap, underlying_tokens, pool_tokens): - - # check if pool is empty: - for i in range(swap.N_COINS()): - assert swap.balances(i) == 0 - - # adding liquidity should not bork: - amounts = [10**17] * swap.N_COINS() - - for token in pool_tokens: - token.approve(swap, 2**256 - 1, sender=bob) - mint_for_testing(bob, 10**18, token, False) - - # check if pool is empty (after minting tokenss): - for i in range(swap.N_COINS()): - assert swap.balances(i) == 0 - - # donate 1 wei and attempt adding liquidity: - pool_tokens[0].transfer(swap, 10, sender=bob) - if 2 in get_asset_types_in_pool(swap): - with boa.reverts(): - # division by zero error expected for rebasing implementation - swap.add_liquidity(amounts, 0, sender=bob) - else: - swap.add_liquidity(amounts, 0, sender=bob) diff --git a/tests/pools/test_exchange.py b/tests/pools/test_exchange.py deleted file mode 100644 index 90c55839..00000000 --- a/tests/pools/test_exchange.py +++ /dev/null @@ -1,241 +0,0 @@ -import boa -import pytest - -pytestmark = pytest.mark.usefixtures("initial_setup") - - -class TestExchange: - @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) - def test_min_dy( - self, - bob, - swap, - pool_type, - pool_tokens, - underlying_tokens, - pool_token_types, - metapool_token_type, - sending, - receiving, - decimals, - ): - amount = 1000 * 10 ** decimals[sending] - initial_receiving = ( - pool_tokens[receiving].balanceOf(bob) if pool_type == 0 else underlying_tokens[receiving].balanceOf(bob) - ) - - min_dy = swap.get_dy(sending, receiving, amount) - # apply rebasing for expected dy - # Down rebasing breaks dy - if pool_type == 0 and pool_token_types[sending] == 2 and sending == 1: - min_dy -= pool_tokens[sending].balanceOf(swap.address) // 1000000 - - swap.exchange(sending, receiving, amount, min_dy - 1, sender=bob) - - if pool_type == 0: - received = pool_tokens[receiving].balanceOf(bob) - else: - received = underlying_tokens[receiving].balanceOf(bob) - - if (pool_type == 0 and 2 in pool_token_types) or (pool_type == 1 and metapool_token_type == 2): - assert abs(received - min_dy - initial_receiving) == pytest.approx(1, abs=received // 1000000) - else: - assert abs(received - min_dy - initial_receiving) <= 1 - - @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) - def test_min_dy_imbalanced( - self, - bob, - swap, - pool_type, - pool_tokens, - underlying_tokens, - pool_token_types, - metapool_token_type, - sending, - receiving, - decimals, - ): - amounts = [1_500_000 * 10**i for i in decimals] - scaler = amounts.copy() # used to scale token amounts when decimals are different - - amounts[sending] = 0 - amounts[receiving] = amounts[receiving] - - swap.add_liquidity(amounts, 0, sender=bob) - - # oracle - rate = 1 - if pool_type == 0: - if pool_token_types[sending] == 1: - rate = rate / (pool_tokens[sending].exchangeRate() / 10**18) - if pool_token_types[receiving] == 1: - rate = rate * (pool_tokens[receiving].exchangeRate() / 10**18) - - elif pool_type == 1: - if metapool_token_type == 1: - if sending == 0: - rate = rate / (underlying_tokens[0].exchangeRate() / 10**18) - - if receiving == 0: - rate = rate * (underlying_tokens[0].exchangeRate() / 10**18) - - # we need to scale these appropriately for tokens with different decimal values - min_dy_sending = swap.get_dy(sending, receiving, scaler[sending]) / scaler[receiving] - min_dy_receiving = swap.get_dy(receiving, sending, scaler[receiving]) / scaler[sending] - - assert min_dy_sending * rate > min_dy_receiving - - class TestExchangeReverts: - @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) - def test_insufficient_balance( - self, charlie, pool_tokens, underlying_tokens, swap, sending, receiving, decimals - ): - - amount = 10 ** decimals[sending] - - for token in pool_tokens + underlying_tokens: - assert token.balanceOf(charlie) == 0 - - # Charlie doesn't have any tokens, all balances are 0 - try: - swap.exchange(sending, receiving, amount + 1, 0, sender=charlie) - assert False - except: # noqa: E722 - assert True - - @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) - @pytest.mark.contains_rebasing_tokens - def test_zero_amount_swap(self, charlie, pool_tokens, underlying_tokens, swap, sending, receiving, decimals): - with boa.reverts(): - swap.exchange(sending, receiving, 0, 0, sender=charlie) - - @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) - def test_min_dy_too_high(self, bob, swap, sending, receiving, decimals): - amount = 10 ** decimals[sending] - min_dy = swap.get_dy(sending, receiving, amount) - with boa.reverts(): - swap.exchange(sending, receiving, amount, min_dy + 2, sender=bob) - - @pytest.mark.parametrize("idx", range(2)) - def test_same_coin(self, bob, swap, idx): - with boa.reverts(): - swap.exchange(idx, idx, 0, 0, sender=bob) - - @pytest.mark.parametrize("idx", [-1, -(2**127)]) - def test_i_below_zero(self, bob, swap, idx): - with boa.reverts(): - swap.exchange(idx, 0, 0, 0, sender=bob) - - @pytest.mark.parametrize("idx", [9, 2**127 - 1]) - def test_i_above_n_coins(self, bob, swap, idx): - with boa.reverts(): - swap.exchange(idx, 0, 0, 0, sender=bob) - - @pytest.mark.parametrize("idx", [-1, -(2**127)]) - def test_j_below_zero(self, bob, swap, idx): - with boa.reverts(): - swap.exchange(0, idx, 0, 0, sender=bob) - - @pytest.mark.parametrize("idx", [9, 2**127 - 1]) - def test_j_above_n_coins(self, bob, swap, idx): - with boa.reverts(): - swap.exchange(0, idx, 0, 0, sender=bob) - - def test_nonpayable(self, swap, bob): - with boa.reverts(): - swap.exchange(0, 1, 0, 0, sender=bob, value=1) - - class TestReceiver: - def test_add_liquidity(self, bob, charlie, swap, deposit_amounts): - swap.add_liquidity(deposit_amounts, 0, charlie, sender=bob) - - assert swap.balanceOf(bob) == 0 - assert swap.balanceOf(charlie) > 0 - - def test_exchange( - self, - bob, - charlie, - swap, - pool_type, - pool_tokens, - underlying_tokens, - decimals, - pool_token_types, - metapool_token_type, - ): - initial_balance = pool_tokens[0].balanceOf(bob) if pool_type == 0 else underlying_tokens[0].balanceOf(bob) - - swap.exchange(1, 0, 1000 * 10**18, 0, charlie, sender=bob) - if pool_type == 0: - assert pool_tokens[0].balanceOf(charlie) > 0 - if pool_token_types[0] != 2: - assert pool_tokens[0].balanceOf(bob) == initial_balance - else: - assert pool_tokens[0].balanceOf(bob) == pytest.approx(initial_balance, rel=2e-2) - else: - assert underlying_tokens[0].balanceOf(charlie) > 0 - if metapool_token_type != 2: - assert underlying_tokens[0].balanceOf(bob) == initial_balance - else: - assert underlying_tokens[0].balanceOf(bob) == pytest.approx(initial_balance, rel=2e-2) - - def test_remove_liquidity( - self, - bob, - swap, - charlie, - pool_type, - pool_tokens, - underlying_tokens, - initial_amounts, - pool_size, - deposit_amounts, - ): - swap.add_liquidity(deposit_amounts, 0, sender=bob) - initial_amount = swap.balanceOf(bob) - withdraw_amount = initial_amount // 4 - swap.remove_liquidity(withdraw_amount, [0] * pool_size, charlie, sender=bob) - - i = 0 - if pool_type == 0: - for coin, amount in zip(pool_tokens, deposit_amounts): - assert coin.balanceOf(swap) + coin.balanceOf(charlie) == pytest.approx( - deposit_amounts[0] * 2, rel=1.5e-2 - ) - i += 1 - else: - for coin, amount in zip(underlying_tokens[:2], deposit_amounts): - assert coin.balanceOf(swap) + coin.balanceOf(charlie) == pytest.approx( - deposit_amounts[0] * 2, rel=1.5e-2 - ) - i += 1 - - assert swap.balanceOf(bob) == pytest.approx(deposit_amounts[0] * pool_size - withdraw_amount, rel=1.5e-2) - assert swap.totalSupply() == pytest.approx(deposit_amounts[0] * 2 * pool_size - withdraw_amount, rel=1.5e-2) - - def test_remove_imbalanced( - self, bob, swap, charlie, pool_type, pool_tokens, underlying_tokens, initial_amounts, deposit_amounts - ): - swap.add_liquidity(deposit_amounts, 0, sender=bob) - initial_balance = swap.balanceOf(bob) - amounts = [i // 4 for i in initial_amounts] - swap.remove_liquidity_imbalance(amounts, initial_balance, charlie, sender=bob) - - if pool_type == 0: - for i, coin in enumerate(pool_tokens): - assert coin.balanceOf(charlie) == pytest.approx(amounts[i], rel=1.5e-2) - assert coin.balanceOf(swap) == pytest.approx(initial_amounts[i] - amounts[i], rel=1.5e-2) - else: - for i, coin in enumerate(underlying_tokens[:2]): - assert coin.balanceOf(charlie) == pytest.approx(amounts[i], rel=1.5e-2) - assert coin.balanceOf(swap) == pytest.approx(initial_amounts[i] - amounts[i], rel=1.5e-2) - - assert swap.balanceOf(bob) / initial_balance == pytest.approx(0.5, rel=1.5e-2) - - def test_remove_one_coin(self, alice, charlie, swap, pool_type, pool_tokens, underlying_tokens): - swap.remove_liquidity_one_coin(10**18, 0, 0, charlie, sender=alice) - - assert swap.balanceOf(charlie) == 0 - assert swap.balanceOf(alice) > 0 diff --git a/tests/pools/test_fees.py b/tests/pools/test_fees.py deleted file mode 100644 index b6576715..00000000 --- a/tests/pools/test_fees.py +++ /dev/null @@ -1,97 +0,0 @@ -import pytest - -pytestmark = pytest.mark.usefixtures("initial_setup") - - -class TestFees: - @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) - def test_admin_balances( - self, bob, swap, pool_type, pool_tokens, underlying_tokens, initial_amounts, sending, receiving - ): - for send, recv in [(sending, receiving), (receiving, sending)]: - swap.exchange( - send, - recv, - initial_amounts[send], - 0, - sender=bob, - ) - - for i in (sending, receiving): - if pool_type == 0: - admin_fee = pool_tokens[i].balanceOf(swap) - swap.balances(i) - assert admin_fee > 0 - else: - admin_fee = underlying_tokens[i].balanceOf(swap) - swap.balances(i) - assert admin_fee > 0 - - @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) - def test_withdraw_one_coin( - self, - alice, - bob, - fee_receiver, - swap, - pool_type, - pool_tokens, - underlying_tokens, - sending, - receiving, - initial_amounts, - ): - swap.exchange( - sending, - receiving, - initial_amounts[sending], - 0, - sender=bob, - ) - - admin_balance = swap.admin_balances(receiving) - - assert admin_balance > 0 - assert swap.admin_balances(sending) == 0 - - swap.withdraw_admin_fees(sender=alice) - swap_balance = ( - pool_tokens[receiving].balanceOf(swap) if pool_type == 0 else underlying_tokens[receiving].balanceOf(swap) - ) - assert swap.balances(receiving) == swap_balance - expected_balance = ( - pool_tokens[receiving].balanceOf(fee_receiver) - if pool_type == 0 - else underlying_tokens[receiving].balanceOf(fee_receiver) - ) - - assert admin_balance == pytest.approx(expected_balance, abs=1) # +- 1 - - def test_no_fees(self, bob, fee_receiver, swap, pool_type, pool_tokens, underlying_tokens): - swap.withdraw_admin_fees(sender=bob) - - if pool_type == 0: - for coin in pool_tokens: - assert coin.balanceOf(fee_receiver) == 0 - else: - for coin in underlying_tokens: - assert coin.balanceOf(fee_receiver) == 0 - - def test_withdraw_admin_fees(self, bob, swap, pool_type, pool_tokens, underlying_tokens, fee_receiver, decimals): - swap.exchange(1, 0, 10_000 * 10 ** decimals[1], 0, sender=bob) - - fees = [] - if pool_type == 0: - for i, coin in enumerate(pool_tokens): - assert coin.balanceOf(fee_receiver) == 0 - fees.append(swap.admin_balances(i)) - else: - for i, coin in enumerate(underlying_tokens[:2]): - assert coin.balanceOf(fee_receiver) == 0 - fees.append(swap.admin_balances(i)) - - swap.withdraw_admin_fees(sender=bob) - if pool_type == 0: - for i, coin in enumerate(pool_tokens): - assert coin.balanceOf(fee_receiver) == pytest.approx(fees[i], abs=1) - else: - for i, coin in enumerate(underlying_tokens[:2]): - assert coin.balanceOf(fee_receiver) == pytest.approx(fees[i], abs=1) diff --git a/tests/pools/test_liquidity.py b/tests/pools/test_liquidity.py deleted file mode 100644 index b26cb192..00000000 --- a/tests/pools/test_liquidity.py +++ /dev/null @@ -1,420 +0,0 @@ -import boa -import pytest - -from tests.fixtures.accounts import add_base_pool_liquidity, mint_account -from tests.fixtures.constants import INITIAL_AMOUNT -from tests.utils.tokens import mint_for_testing -from tests.utils.transactions import call_returning_result_and_logs - - -class TestLiquidityMethods: - @pytest.mark.usefixtures("initial_setup") - class TestAddLiquidity: - def test_add_liquidity( - self, - bob, - swap, - pool_type, - pool_tokens, - underlying_tokens, - deposit_amounts, - initial_amounts, - pool_token_types, - metapool_token_type, - ): - swap.add_liquidity(deposit_amounts, 0, sender=bob) - is_ideal = True - - if pool_type == 0: - for i, (pool_token, amount) in enumerate(zip(pool_tokens, deposit_amounts)): - if pool_token_types[i] == 2: - is_ideal = False - assert pool_token.balanceOf(bob) >= initial_amounts[i] - deposit_amounts[i] - assert pool_token.balanceOf(swap.address) >= deposit_amounts[i] * 2 - else: - assert pool_token.balanceOf(bob) == initial_amounts[i] - deposit_amounts[i] - assert pool_token.balanceOf(swap.address) == deposit_amounts[i] * 2 - - if pool_token_types[i] == 1: - is_ideal = False - - ideal = len(pool_tokens) * INITIAL_AMOUNT // 2 * 10**18 - if is_ideal: - assert abs(swap.balanceOf(bob) - ideal) <= 1 - assert abs(swap.totalSupply() - ideal * 2) <= 2 - else: - if metapool_token_type == 2: - assert underlying_tokens[0].balanceOf(bob) >= initial_amounts[0] - deposit_amounts[0] - assert underlying_tokens[0].balanceOf(swap.address) >= deposit_amounts[0] * 2 - else: - assert underlying_tokens[0].balanceOf(bob) == initial_amounts[0] - deposit_amounts[0] - assert underlying_tokens[0].balanceOf(swap.address) == deposit_amounts[0] * 2 - - if metapool_token_type == 0: - ideal = INITIAL_AMOUNT * 10**18 # // 2 * 2 - assert abs(swap.balanceOf(bob) - ideal) <= 1 - assert abs(swap.totalSupply() - ideal * 2) <= 2 - - assert underlying_tokens[1].balanceOf(bob) == initial_amounts[1] - deposit_amounts[1] - assert underlying_tokens[1].balanceOf(swap) == deposit_amounts[1] * 2 - - @pytest.mark.parametrize("idx", (0, 1)) - def test_add_one_coin( - self, - bob, - swap, - pool_type, - pool_tokens, - underlying_tokens, - deposit_amounts, - initial_amounts, - pool_token_types, - metapool_token_type, - idx, - ): - amounts = [0] * len(pool_tokens) - amounts[idx] = deposit_amounts[idx] - - swap.add_liquidity(amounts, 0, sender=bob) - is_ideal = True - - if pool_type == 0: - for i, pool_token in enumerate(pool_tokens): - if pool_token_types[i] == 2: - is_ideal = False - assert pool_token.balanceOf(bob) >= initial_amounts[i] - amounts[i] - 1 - assert pool_token.balanceOf(swap.address) >= deposit_amounts[i] + amounts[i] - 1 - else: - assert pool_token.balanceOf(bob) == initial_amounts[i] - amounts[i] - assert pool_token.balanceOf(swap.address) == deposit_amounts[i] + amounts[i] - else: - if metapool_token_type == 2: - is_ideal = False - assert underlying_tokens[0].balanceOf(bob) >= initial_amounts[0] - amounts[0] - 1 - assert underlying_tokens[0].balanceOf(swap.address) >= deposit_amounts[0] + amounts[0] - 1 - else: - assert underlying_tokens[0].balanceOf(bob) == initial_amounts[0] - amounts[0] - assert underlying_tokens[0].balanceOf(swap) == deposit_amounts[0] + amounts[0] - - assert underlying_tokens[1].balanceOf(bob) == initial_amounts[1] - amounts[1] - assert underlying_tokens[1].balanceOf(swap) == deposit_amounts[1] + amounts[1] - - difference = abs(swap.balanceOf(bob) - deposit_amounts[idx]) - if is_ideal: - assert difference / (deposit_amounts[idx]) < 0.01 - else: - assert difference / (deposit_amounts[idx]) < 0.02 - - def test_insufficient_balance(self, charlie, swap, pool_type, decimals, meta_decimals): - if pool_type == 0: - amounts = [(10**i) for i in decimals] - else: - amounts = [(10**i) for i in [meta_decimals, 18]] - - with boa.reverts(): # invalid approval or balance - swap.add_liquidity(amounts, 0, sender=charlie) - - def test_min_amount_too_high(self, bob, swap, pool_type, deposit_amounts, pool_tokens): - size = 2 - if pool_type == 0: - size = len(pool_tokens) - - with boa.reverts(): - swap.add_liquidity(deposit_amounts, size * INITIAL_AMOUNT // 2 * 10**18 * 101 // 100, sender=bob) - - def test_event(self, bob, swap, pool_type, deposit_amounts, pool_tokens, pool_token_types, metapool_token_type): - size = 2 - check_invariant = True - if pool_type == 0: - size = len(pool_tokens) - - for t in pool_token_types: - if t != 0: - check_invariant = False - - if pool_type == 1: - if metapool_token_type != 0: - check_invariant = False - - _, events = call_returning_result_and_logs(swap, "add_liquidity", deposit_amounts, 0, sender=bob) - - assert len(events) == 4 # Transfer token1, Transfer token2, Transfer LP, Add liquidity - if check_invariant: - assert ( - repr(events[3]) == f"AddLiquidity(provider={bob}, token_amounts={deposit_amounts}, fees=[0, 0], " - f"invariant={size * INITIAL_AMOUNT * 10**18}, token_supply={swap.totalSupply()})" - ) - - def test_send_eth(self, bob, swap, deposit_amounts): - with boa.reverts(): - swap.add_liquidity(deposit_amounts, 0, sender=bob, value=1) - - class TestInitialLiquidity: - @pytest.fixture(scope="module") - def initial_setup_alice( - self, - alice, - deposit_amounts, - swap, - pool_type, - base_pool, - base_pool_tokens, - base_pool_decimals, - base_pool_lp_token, - initial_balance, - initial_amounts, - pool_tokens, - underlying_tokens, - ): - with boa.env.anchor(): - mint_for_testing(alice, 1 * 10**18, None, True) - - if pool_type == 0: - - mint_account(alice, pool_tokens, initial_balance, initial_amounts) - with boa.env.prank(alice): - for token in pool_tokens: - token.approve(swap.address, 2**256 - 1) - - else: - add_base_pool_liquidity(alice, base_pool, base_pool_tokens, base_pool_decimals) - mint_for_testing(alice, initial_amounts[0], underlying_tokens[0], False) - - with boa.env.prank(alice): - for token in underlying_tokens: - token.approve(swap.address, 2**256 - 1) - - yield - - @pytest.mark.parametrize("min_amount", [0, 10**18]) - def test_initial( - self, - alice, - initial_setup_alice, - swap, - pool_type, - pool_tokens, - underlying_tokens, - pool_token_types, - metapool_token_type, - min_amount, - decimals, - meta_decimals, - deposit_amounts, - initial_amounts, - ): - swap.add_liquidity( - deposit_amounts, - len(pool_tokens) * min_amount, - sender=alice, - ) - - token_types = pool_token_types if pool_type == 0 else [metapool_token_type, 18] - - for coin, und_coin, amount, initial, pool_token_type in zip( - pool_tokens, underlying_tokens, deposit_amounts, initial_amounts, token_types - ): - if pool_type == 0: - assert coin.balanceOf(alice) == pytest.approx(initial - amount, rel=1.5e-2) - assert coin.balanceOf(swap) == pytest.approx(amount, rel=1.5e-2) - else: - assert und_coin.balanceOf(alice) == pytest.approx(initial - amount, rel=1.5e-2) - assert und_coin.balanceOf(swap) == pytest.approx(amount, rel=1.5e-2) - - @pytest.mark.usefixtures("initial_setup") - class TestRemoveLiquidity: - @pytest.mark.parametrize("min_amount", (0, 1)) - def test_remove_liquidity( - self, alice, swap, pool_type, pool_tokens, underlying_tokens, min_amount, deposit_amounts - ): - swap.remove_liquidity(swap.balanceOf(alice), [i * min_amount for i in deposit_amounts], sender=alice) - - coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] - - for coin, amount in zip(coins, deposit_amounts): - assert coin.balanceOf(alice) == pytest.approx(amount * 2, rel=1.5e-2) - assert coin.balanceOf(swap) == 0 - - assert swap.balanceOf(alice) == 0 - assert swap.totalSupply() == 0 - - def test_remove_partial(self, alice, swap, pool_type, pool_tokens, underlying_tokens, pool_size): - initial_amount = swap.balanceOf(alice) - withdraw_amount = initial_amount // 2 - coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] - swap.remove_liquidity(withdraw_amount, [0] * pool_size, sender=alice) - - for coin in coins: - assert coin.balanceOf(swap) + coin.balanceOf(alice) == pytest.approx(initial_amount, rel=1.5e-2) - - assert swap.balanceOf(alice) == initial_amount - withdraw_amount - assert swap.totalSupply() == initial_amount - withdraw_amount - - @pytest.mark.parametrize("idx", range(2)) - def test_below_min_amount(self, alice, swap, initial_amounts, idx): - min_amount = initial_amounts.copy() - min_amount[idx] += 1 - - with boa.reverts(): - swap.remove_liquidity(swap.balanceOf(alice), min_amount, sender=alice) - - def test_amount_exceeds_balance(self, alice, swap, pool_size): - with boa.reverts(): - swap.remove_liquidity(swap.balanceOf(alice) + 1, [0] * pool_size, sender=alice) - - def test_event(self, alice, bob, swap, pool_type, pool_size): - swap.transfer(bob, 10**18, sender=alice) - _, events = call_returning_result_and_logs( - swap, "remove_liquidity", 10**18, [0] * pool_size, sender=alice - ) - - assert f"RemoveLiquidity(provider={alice}" in repr(events[3]) - - @pytest.mark.usefixtures("initial_setup") - class TestRemoveLiquidityImbalance: - @pytest.mark.parametrize("divisor", [2, 5, 10]) - def test_remove_balanced( - self, alice, swap, pool_type, pool_tokens, underlying_tokens, divisor, deposit_amounts, initial_amounts - ): - initial_balance = swap.balanceOf(alice) - amounts = [i // divisor for i in deposit_amounts] - swap.remove_liquidity_imbalance(amounts, initial_balance, sender=alice) - - coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] - - for i, coin in enumerate(coins): - assert coin.balanceOf(alice) == pytest.approx( - amounts[i] + initial_amounts[i] - deposit_amounts[i], rel=1.5e-2 - ) - assert coin.balanceOf(swap) == pytest.approx(deposit_amounts[i] - amounts[i], rel=1.5e-2) - - assert swap.balanceOf(alice) / initial_balance == pytest.approx(1 - 1 / divisor, rel=1.5e-2) - - @pytest.mark.parametrize("idx", range(2)) - def test_remove_one( - self, - alice, - swap, - pool_type, - pool_tokens, - underlying_tokens, - pool_size, - idx, - deposit_amounts, - initial_amounts, - ): - amounts = [0] * pool_size - amounts[idx] = deposit_amounts[idx] // 2 - - lp_balance = pool_size * deposit_amounts[idx] - swap.remove_liquidity_imbalance(amounts, lp_balance, sender=alice) - - coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] - - for i, coin in enumerate(coins): - assert coin.balanceOf(alice) == pytest.approx( - amounts[i] + initial_amounts[i] - deposit_amounts[i], rel=1.5e-2 - ) - assert coin.balanceOf(swap) == pytest.approx(deposit_amounts[i] - amounts[i], rel=1.5e-2) - - actual_balance = swap.balanceOf(alice) - actual_total_supply = swap.totalSupply() - ideal_balance = (2 * pool_size - 1) * lp_balance / (2 * pool_size) - - assert actual_balance == actual_total_supply - assert ideal_balance * 0.9994 < actual_balance - assert actual_balance < ideal_balance * 1.07 - - @pytest.mark.parametrize("divisor", [1, 2, 10]) - def test_exceed_max_burn(self, alice, swap, pool_size, divisor, deposit_amounts): - amounts = [i // divisor for i in deposit_amounts] - max_burn = pool_size * 1_000_000 * 10**18 // divisor - - with boa.reverts(): - swap.remove_liquidity_imbalance(amounts, max_burn - 1, sender=alice) - - def test_cannot_remove_zero(self, alice, swap, pool_size): - with boa.reverts(): - swap.remove_liquidity_imbalance([0] * pool_size, 0, sender=alice) - - def test_no_totalsupply(self, alice, swap, pool_size): - swap.remove_liquidity(swap.totalSupply(), [0] * pool_size, sender=alice) - with boa.reverts(): - swap.remove_liquidity_imbalance([0] * pool_size, 0, sender=alice) - - def test_event(self, alice, bob, swap, pool_type, pool_size, deposit_amounts): - swap.transfer(bob, swap.balanceOf(alice), sender=alice) - amounts = [i // 5 for i in deposit_amounts] - max_burn = pool_size * 1_000_000 * 10**18 - - _, events = call_returning_result_and_logs( - swap, "remove_liquidity_imbalance", amounts, max_burn, sender=bob - ) - - assert f"RemoveLiquidityImbalance(provider={bob}" in repr(events[3]) - - @pytest.mark.usefixtures("initial_setup") - class TestRemoveLiquidityOneCoin: - @pytest.mark.parametrize("idx", range(2)) - def test_amount_received(self, alice, swap, pool_type, pool_tokens, underlying_tokens, decimals, idx): - coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] - initial_amount = coins[idx].balanceOf(alice) - - swap.remove_liquidity_one_coin(10**18, idx, 0, sender=alice) - ideal = 10 ** decimals[idx] - assert ideal * 0.99 <= coins[idx].balanceOf(alice) - initial_amount <= ideal - - @pytest.mark.parametrize("idx", range(2)) - @pytest.mark.parametrize("divisor", [1, 5, 42]) - def test_lp_token_balance(self, alice, swap, idx, divisor): - initial_amount = swap.balanceOf(alice) - amount = initial_amount // divisor - - if divisor == 1: - with boa.reverts(): - swap.remove_liquidity_one_coin(amount, idx, 0, sender=alice) - else: - swap.remove_liquidity_one_coin(amount, idx, 0, sender=alice) - - assert swap.balanceOf(alice) + amount == initial_amount - - @pytest.mark.parametrize("idx", range(2)) - def test_expected_vs_actual(self, alice, swap, pool_type, pool_tokens, underlying_tokens, idx): - coins = pool_tokens if pool_type == 0 else underlying_tokens[:2] - initial_amount = coins[idx].balanceOf(alice) - amount = swap.balanceOf(alice) // 10 - - expected = swap.calc_withdraw_one_coin(amount, idx) - swap.remove_liquidity_one_coin(amount, idx, 0, sender=alice) - assert coins[idx].balanceOf(alice) == expected + initial_amount - - @pytest.mark.parametrize("idx", range(2)) - def test_below_min_amount(self, alice, swap, idx): - amount = swap.balanceOf(alice) - - expected = swap.calc_withdraw_one_coin(amount, idx) - with boa.reverts(): - swap.remove_liquidity_one_coin(amount, idx, expected + 1, sender=alice) - - @pytest.mark.parametrize("idx", range(2)) - def test_amount_exceeds_balance(self, bob, swap, idx): - with boa.reverts(): - swap.remove_liquidity_one_coin(1, idx, 0, sender=bob) - - def test_below_zero(self, alice, swap): - with boa.reverts(): - swap.remove_liquidity_one_coin(1, -1, 0, sender=alice) - - def test_above_n_coins(self, alice, swap, pool_size): - with boa.reverts(): - swap.remove_liquidity_one_coin(1, pool_size, 0, sender=alice) - - @pytest.mark.parametrize("idx", range(2)) - def test_event(self, alice, bob, swap, idx, pool_type): - swap.transfer(bob, 10**18, sender=alice) - _, events = call_returning_result_and_logs(swap, "remove_liquidity_one_coin", 10**18, idx, 0, sender=bob) - - if pool_type == 0: - assert f"RemoveLiquidityOne(provider={bob}" in repr(events[2]) - else: - assert f"RemoveLiquidityOne(provider={bob}" in repr(events[3]) diff --git a/tests/test_factory.py b/tests/test_factory.py deleted file mode 100644 index e0f3cacc..00000000 --- a/tests/test_factory.py +++ /dev/null @@ -1,252 +0,0 @@ -import itertools - -import boa -import pytest - -MAX_COINS = 8 - - -class TestFactory: - class TestGeneral: - def test_get_A(self, factory, swap): - assert factory.get_A(swap.address) == swap.A() - - def test_get_fees(self, factory, swap): - assert factory.get_fees(swap.address) == (swap.fee(), swap.admin_fee()) - - def test_get_admin_balances(self, factory, swap, pool_size): - balances = [swap.admin_balances(i) for i in range(pool_size)] - assert factory.get_admin_balances(swap.address) == balances - - def test_fee_receiver(self, factory, fee_receiver): - assert factory.fee_receiver() == fee_receiver - - @pytest.mark.only_for_pool_type(0) - class TestBasic: - @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) - def test_find_pool_for_coins(self, factory, swap, pool_tokens, sending, receiving): - assert ( - factory.find_pool_for_coins(pool_tokens[sending].address, pool_tokens[receiving].address) - == swap.address - ) - - def test_get_n_coins(self, factory, swap, pool_tokens, pool_size): - assert factory.get_n_coins(swap.address) == 2 - - def test_get_coins(self, factory, swap, pool_tokens, pool_size): - assert factory.get_coins(swap.address) == [pt.address for pt in pool_tokens] - - def test_get_decimals(self, factory, swap, decimals): - assert factory.get_decimals(swap.address) == decimals - - def test_get_balances(self, factory, swap, pool_size): - assert factory.get_balances(swap.address) == [swap.balances(i) for i in range(pool_size)] - - @pytest.mark.only_for_pool_type(0) - def test_get_underlying_balances(self, factory, swap): - with boa.reverts() as e: - factory.get_underlying_balances(swap.address) - assert str(e) == "dev: pool is not a metapool" - - def test_get_A(self, factory, swap): - assert factory.get_A(swap.address) == swap.A() - - def test_get_fees(self, factory, swap): - assert factory.get_fees(swap.address) == (swap.fee(), swap.admin_fee()) - - @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) - def test_get_coin_indices(self, factory, swap, sending, receiving, pool_tokens): - i, j, is_underlying = factory.get_coin_indices( - swap.address, pool_tokens[sending].address, pool_tokens[receiving].address - ) - assert i == sending - assert j == receiving - - def test_get_implementation_address(self, factory, swap, amm_implementation): - assert factory.get_implementation_address(swap.address) == amm_implementation.address - - def test_is_meta(self, factory, swap): - assert factory.is_meta(swap.address) is False - - def test_get_pool_types(self, factory, swap, pool_token_types): - assert factory.get_pool_asset_types(swap.address) == list(pool_token_types) - - @pytest.mark.only_for_pool_type(1) - class TestMeta: - @pytest.mark.parametrize("sending,receiving", [(0, 1), (1, 0)]) - def test_find_pool_for_coins(self, factory, swap, underlying_tokens, sending, receiving): - assert ( - factory.find_pool_for_coins(underlying_tokens[sending].address, underlying_tokens[receiving].address) - == swap.address - ) - - @pytest.mark.parametrize("idx", range(1, 4)) - def test_find_pool_for_coins_underlying(self, factory, swap, underlying_tokens, idx): - assert factory.find_pool_for_coins(underlying_tokens[0], underlying_tokens[idx]) == swap.address - assert factory.find_pool_for_coins(underlying_tokens[idx], underlying_tokens[0]) == swap.address - - def test_get_meta_n_coins(self, factory, swap): - assert factory.get_meta_n_coins(swap.address) == (2, 4) - - def test_get_underlying_coins(self, factory, swap, underlying_tokens): - tokens = [underlying_tokens[0]] + underlying_tokens[2:] - assert factory.get_underlying_coins(swap.address) == [t.address for t in tokens] - - def test_get_underlying_decimals(self, factory, swap, base_pool_decimals, pool_type): - assert factory.get_underlying_decimals(swap.address) == [18] + base_pool_decimals - - def test_get_metapool_rates(self, factory, swap, base_pool, initial_setup): - assert factory.get_metapool_rates(swap.address) == [10**18, base_pool.get_virtual_price()] - - def test_get_underlying_balances(self, factory, swap, base_pool, initial_setup): - assert factory.get_metapool_rates(swap.address) == [10**18, base_pool.get_virtual_price()] - - @pytest.mark.parametrize("sending,receiving", itertools.permutations(range(1, 4), 2)) - def test_find_pool_underlying_base_pool_only( - self, factory, underlying_tokens, sending, receiving, zero_address - ): - assert factory.find_pool_for_coins(underlying_tokens[sending], underlying_tokens[receiving]) == zero_address - - @pytest.mark.parametrize("sending,receiving", itertools.permutations(range(2, 5), 2)) - def test_get_coin_indices_underlying(self, factory, swap, sending, receiving, underlying_tokens): - i, j, is_underlying = factory.get_coin_indices( - swap, underlying_tokens[sending], underlying_tokens[receiving] - ) - assert i == sending - 1 - assert j == receiving - 1 - assert is_underlying is True - - @pytest.mark.parametrize("idx", range(1, 4)) - def test_get_coin_indices_reverts(self, factory, swap, base_pool_lp_token, underlying_tokens, idx): - with boa.reverts(): - factory.get_coin_indices(swap.address, base_pool_lp_token.address, underlying_tokens[idx]) - - def test_get_implementation_address(self, factory, swap, amm_implementation_meta): - assert factory.get_implementation_address(swap.address) == amm_implementation_meta.address - - def test_is_meta(self, factory, swap): - assert factory.is_meta(swap.address) is True - - class TestFactoryAddPools: - @pytest.fixture - def empty_factory(self, deployer, fee_receiver, owner): - with boa.env.prank(deployer): - _factory = boa.load( - "contracts/main/CurveStableSwapFactoryNG.vy", - fee_receiver, - owner, - ) - return _factory - - @pytest.fixture - def empty_factory_with_implementations( - self, - empty_factory, - owner, - gauge_implementation, - views_implementation, - math_implementation, - amm_implementation, - amm_implementation_meta, - ): - with boa.env.prank(owner): - empty_factory.set_gauge_implementation(gauge_implementation.address) - empty_factory.set_views_implementation(views_implementation.address) - empty_factory.set_math_implementation(math_implementation.address) - - empty_factory.set_pool_implementations(0, amm_implementation.address) - empty_factory.set_metapool_implementations(0, amm_implementation_meta.address) - - return empty_factory - - def test_add_base_pool_already_exists( - self, - owner, - factory, - add_base_pool, - base_pool, - base_pool_lp_token, - base_pool_tokens, - ): - with boa.reverts(): - factory.add_base_pool( - base_pool.address, - base_pool_lp_token.address, - [0] * len(base_pool_tokens), - len(base_pool_tokens), - sender=owner, - ) - - def test_add_base_pool_only_admin( - self, - factory, - bob, - base_pool, - base_pool_lp_token, - base_pool_tokens, - ): - with boa.reverts(): - factory.add_base_pool( - base_pool.address, - base_pool_lp_token.address, - [0] * len(base_pool_tokens), - len(base_pool_tokens), - sender=bob, - ) - - def test_deploy_plain_pool( - self, empty_factory_with_implementations, amm_interface, pool_tokens, pool_size, zero_address - ): - swap_address = empty_factory_with_implementations.deploy_plain_pool( - "test", - "test", - [t.address for t in pool_tokens], - 2000, - 1000000, - 20000000000, - 866, - 0, - [0] * pool_size, - [bytes(b"")] * pool_size, - [zero_address] * pool_size, - ) - assert swap_address != zero_address - - swap = amm_interface.at(swap_address) - assert swap.coins(0) == pool_tokens[0].address - assert swap.coins(1) == pool_tokens[1].address - - assert swap.A() == 2000 - assert swap.fee() == 1000000 - - assert empty_factory_with_implementations.pool_count() == 1 - assert empty_factory_with_implementations.pool_list(0) == swap.address - assert empty_factory_with_implementations.get_decimals(swap) == [t.decimals() for t in pool_tokens] - - def test_pool_count( - self, - empty_factory_with_implementations, - swap, - add_base_pool, - amm_interface, - set_pool_implementations, - pool_tokens, - pool_size, - zero_address, - ): - assert empty_factory_with_implementations.pool_count() == 0 - - empty_factory_with_implementations.deploy_plain_pool( - "test", - "test", - [t.address for t in pool_tokens], - 2000, - 1000000, - 20000000000, - 866, - 0, - [0] * pool_size, - [bytes(b"")] * pool_size, - [zero_address] * pool_size, - ) - assert empty_factory_with_implementations.pool_count() == 1 diff --git a/tests/test_token.py b/tests/test_token.py deleted file mode 100644 index c3283391..00000000 --- a/tests/test_token.py +++ /dev/null @@ -1,370 +0,0 @@ -import boa -import pytest -from eip712.messages import EIP712Message -from eth_account._utils.signing import to_bytes32 - -from tests.utils.transactions import call_returning_result_and_logs - -added_liquidity = pytest.mark.usefixtures("initial_setup") - - -class TestPoolToken: - class TestTokenApprove: - @pytest.mark.parametrize("idx", range(4)) - def test_initial_approval_is_zero(self, swap, alice, accounts, idx): - assert swap.allowance(alice, accounts[idx]) == 0 - - def test_approve(self, swap, alice, bob): - swap.approve(bob, 10**19, sender=alice) - assert swap.allowance(alice, bob) == 10**19 - - def test_modify_approve_zero_nonzero(self, swap, alice, bob): - with boa.env.prank(alice): - swap.approve(bob, 10**19) - swap.approve(bob, 0) - swap.approve(bob, 12345678) - - assert swap.allowance(alice, bob) == 12345678 - - def test_revoke_approve(self, swap, alice, bob): - with boa.env.prank(alice): - swap.approve(bob, 10**19) - swap.approve(bob, 0) - - assert swap.allowance(alice, bob) == 0 - - def test_approve_self(self, swap, alice): - swap.approve(alice, 10**19, sender=alice) - assert swap.allowance(alice, alice) == 10**19 - - def test_only_affects_target(self, swap, alice, bob): - swap.approve(bob, 10**19, sender=alice) - assert swap.allowance(bob, alice) == 0 - - def test_returns_true(self, swap, alice, bob): - tx = swap.approve(bob, 10**19, sender=alice) - assert tx is True - - def test_approval_event_fires(self, alice, bob, swap): - value = 10**19 - res, events = call_returning_result_and_logs(swap, "approve", bob, value, sender=alice) - - assert res is True - assert len(events) == 1 - assert repr(events[0]) == f"Approval(owner={alice}, spender={bob}, value={value})" - - @added_liquidity - def test_infinite_approval(self, swap, alice, bob): - swap.approve(bob, 2**256 - 1, sender=alice) - swap.transferFrom(alice, bob, 10**18, sender=bob) - - assert swap.allowance(alice, bob) == 2**256 - 1 - - @staticmethod - def permit_class(swap) -> type[EIP712Message]: - class Permit(EIP712Message): - # EIP-712 Domain Fields - _name_: "string" = swap.name() # noqa: F821 - _version_: "string" = swap.version() # noqa: F821 - _chainId_: "uint256" = boa.env.chain.chain_id # noqa: F821 - _verifyingContract_: "address" = swap.address # noqa: F821 - _salt_: "bytes32" = swap.salt() # noqa: F821 - - # EIP-2612 Data Fields - owner: "address" # noqa: F821 - spender: "address" # noqa: F821 - value: "uint256" # noqa: F821 - nonce: "uint256" # noqa: F821 - deadline: "uint256" = 2**256 - 1 # noqa: F821 - - return Permit - - def test_permit(self, eth_acc, bob, swap): - value = 2**256 - 1 - permit = self.permit_class(swap)(owner=eth_acc.address, spender=bob, value=value, nonce=0) - sig = eth_acc.sign_message(permit.signable_message) - - res, events = call_returning_result_and_logs( - swap, - "permit", - eth_acc.address, - bob, - 2**256 - 1, - 2**256 - 1, - sig.v, - to_bytes32(sig.r), - to_bytes32(sig.s), - sender=bob, - ) - - assert swap.allowance(eth_acc.address, bob) == 2**256 - 1 - assert res is True - assert len(events) == 1 - assert repr(events[0]) == f"Approval(owner={eth_acc.address}, spender={bob}, value={value})" - assert swap.nonces(eth_acc.address) == 1 - - def test_permit_contract(self, eth_acc, bob, swap): - # based on https://eips.ethereum.org/EIPS/eip-1271 - src = """ - # @version ^0.3.9 - OWNER: public(immutable(address)) - - @external - def __init__(): - OWNER = msg.sender - - @view - @external - def isValidSignature(_hash: bytes32, _signature: Bytes[65]) -> bytes32: - signer: address = self._recover_signer(_hash, _signature) - if signer == OWNER: - return 0x1626ba7e00000000000000000000000000000000000000000000000000000000 - return 0xffffffff00000000000000000000000000000000000000000000000000000000 - - @view - @internal - def _recover_signer(_hash: bytes32, _signature: Bytes[65]) -> address: - v: uint256 = convert(slice(_signature, 64, 1), uint256) - r: uint256 = convert(slice(_signature, 0, 32), uint256) - s: uint256 = convert(slice(_signature, 32, 32), uint256) - return ecrecover(_hash, v, r, s) - """ - with boa.env.prank(eth_acc.address): - mock_contract = boa.loads(src) - - permit = self.permit_class(swap)(owner=mock_contract.address, spender=bob, value=2**256 - 1, nonce=0) - sig = eth_acc.sign_message(permit.signable_message) - - res, events = call_returning_result_and_logs( - swap, - "permit", - mock_contract.address, - bob, - 2**256 - 1, - 2**256 - 1, - sig.v, - to_bytes32(sig.r), - to_bytes32(sig.s), - sender=bob, - ) - assert swap.allowance(mock_contract.address, bob) == 2**256 - 1 - assert res is True - assert len(events) == 1 - - @added_liquidity - class TestTokenTransfer: - def test_sender_balance_decreases(self, alice, bob, swap): - sender_balance = swap.balanceOf(alice) - amount = sender_balance // 4 - - swap.transfer(bob, amount, sender=alice) - - assert swap.balanceOf(alice) == sender_balance - amount - - def test_receiver_balance_increases(self, alice, bob, swap): - receiver_balance = swap.balanceOf(bob) - amount = swap.balanceOf(alice) // 4 - - swap.transfer(bob, amount, sender=alice) - - assert swap.balanceOf(bob) == receiver_balance + amount - - def test_total_supply_not_affected(self, alice, bob, swap): - total_supply = swap.totalSupply() - amount = swap.balanceOf(alice) - - swap.transfer(bob, amount, sender=alice) - - assert swap.totalSupply() == total_supply - - def test_returns_true(self, alice, bob, swap): - amount = swap.balanceOf(alice) - res = swap.transfer(bob, amount, sender=alice) - - assert res is True - - def test_transfer_full_balance(self, alice, bob, swap): - amount = swap.balanceOf(alice) - receiver_balance = swap.balanceOf(bob) - - swap.transfer(bob, amount, sender=alice) - - assert swap.balanceOf(alice) == 0 - assert swap.balanceOf(bob) == receiver_balance + amount - - def test_transfer_zero_tokens(self, alice, bob, swap): - sender_balance = swap.balanceOf(alice) - receiver_balance = swap.balanceOf(bob) - - swap.transfer(bob, 0, sender=alice) - - assert swap.balanceOf(alice) == sender_balance - assert swap.balanceOf(bob) == receiver_balance - - def test_transfer_to_self(self, alice, bob, swap): - sender_balance = swap.balanceOf(alice) - amount = sender_balance // 4 - - swap.transfer(alice, amount, sender=alice) - - assert swap.balanceOf(alice) == sender_balance - - def test_insufficient_balance(self, alice, bob, swap): - balance = swap.balanceOf(alice) - - with boa.reverts(): - swap.transfer(bob, balance + 1, sender=alice) - - def test_transfer_event_fires(self, alice, bob, swap): - amount = swap.balanceOf(alice) - _, events = call_returning_result_and_logs(swap, "transfer", bob, amount, sender=alice) - - assert len(events) == 1 - assert repr(events[0]) == f"Transfer(sender={alice}, receiver={bob}, value={amount})" - - @added_liquidity - class TestTokenTransferFrom: - def test_sender_balance_decreases(self, alice, bob, charlie, swap): - sender_balance = swap.balanceOf(alice) - amount = sender_balance // 4 - - swap.approve(bob, amount, sender=alice) - swap.transferFrom(alice, charlie, amount, sender=bob) - - assert swap.balanceOf(alice) == sender_balance - amount - - def test_receiver_balance_increases(self, alice, bob, charlie, swap): - receiver_balance = swap.balanceOf(charlie) - amount = swap.balanceOf(alice) // 4 - - swap.approve(bob, amount, sender=alice) - swap.transferFrom(alice, charlie, amount, sender=bob) - - assert swap.balanceOf(charlie) == receiver_balance + amount - - def test_caller_balance_not_affected(self, alice, bob, charlie, swap): - caller_balance = swap.balanceOf(bob) - amount = swap.balanceOf(alice) - - swap.approve(bob, amount, sender=alice) - swap.transferFrom(alice, charlie, amount, sender=bob) - - assert swap.balanceOf(bob) == caller_balance - - def test_caller_approval_affected(self, alice, bob, charlie, swap): - approval_amount = swap.balanceOf(alice) - transfer_amount = approval_amount // 4 - - swap.approve(bob, approval_amount, sender=alice) - swap.transferFrom(alice, charlie, transfer_amount, sender=bob) - - assert swap.allowance(alice, bob) == approval_amount - transfer_amount - - def test_receiver_approval_not_affected(self, alice, bob, charlie, swap): - approval_amount = swap.balanceOf(alice) - transfer_amount = approval_amount // 4 - - swap.approve(bob, approval_amount, sender=alice) - swap.approve(charlie, approval_amount, sender=alice) - swap.transferFrom(alice, charlie, transfer_amount, sender=bob) - - assert swap.allowance(alice, charlie) == approval_amount - - def test_total_supply_not_affected(self, alice, bob, charlie, swap): - total_supply = swap.totalSupply() - amount = swap.balanceOf(alice) - - swap.approve(bob, amount, sender=alice) - swap.transferFrom(alice, charlie, amount, sender=bob) - - assert swap.totalSupply() == total_supply - - def test_returns_true(self, alice, bob, charlie, swap): - amount = swap.balanceOf(alice) - swap.approve(bob, amount, sender=alice) - res = swap.transferFrom(alice, charlie, amount, sender=bob) - - assert res is True - - def test_transfer_full_balance(self, alice, bob, charlie, swap): - amount = swap.balanceOf(alice) - receiver_balance = swap.balanceOf(charlie) - - swap.approve(bob, amount, sender=alice) - swap.transferFrom(alice, charlie, amount, sender=bob) - - assert swap.balanceOf(alice) == 0 - assert swap.balanceOf(charlie) == receiver_balance + amount - - def test_transfer_zero_tokens(self, alice, bob, charlie, swap): - sender_balance = swap.balanceOf(alice) - receiver_balance = swap.balanceOf(charlie) - - swap.approve(bob, sender_balance, sender=alice) - swap.transferFrom(alice, charlie, 0, sender=bob) - - assert swap.balanceOf(alice) == sender_balance - assert swap.balanceOf(charlie) == receiver_balance - - def test_transfer_zero_tokens_without_approval(self, alice, bob, charlie, swap): - sender_balance = swap.balanceOf(alice) - receiver_balance = swap.balanceOf(charlie) - - swap.transferFrom(alice, charlie, 0, sender=bob) - - assert swap.balanceOf(alice) == sender_balance - assert swap.balanceOf(charlie) == receiver_balance - - def test_insufficient_balance(self, alice, bob, charlie, swap): - balance = swap.balanceOf(alice) - - swap.approve(bob, balance + 1, sender=alice) - with boa.reverts(): - swap.transferFrom(alice, charlie, balance + 1, sender=bob) - - def test_insufficient_approval(self, alice, bob, charlie, swap): - balance = swap.balanceOf(alice) - - swap.approve(bob, balance - 1, sender=alice) - with boa.reverts(): - swap.transferFrom(alice, charlie, balance, sender=bob) - - def test_no_approval(self, alice, bob, charlie, swap): - balance = swap.balanceOf(alice) - - with boa.reverts(): - swap.transferFrom(alice, charlie, balance, sender=bob) - - def test_revoked_approval(self, alice, bob, charlie, swap): - balance = swap.balanceOf(alice) - - swap.approve(bob, balance, sender=alice) - swap.approve(bob, 0, sender=alice) - - with boa.reverts(): - swap.transferFrom(alice, charlie, balance, sender=bob) - - def test_transfer_to_self(self, alice, bob, swap): - sender_balance = swap.balanceOf(alice) - amount = sender_balance // 4 - - swap.approve(alice, sender_balance, sender=alice) - swap.transferFrom(alice, alice, amount, sender=alice) - - assert swap.balanceOf(alice) == sender_balance - assert swap.allowance(alice, alice) == sender_balance - amount - - def test_transfer_to_self_no_approval(self, alice, bob, swap): - amount = swap.balanceOf(alice) - - with boa.reverts(): - swap.transferFrom(alice, alice, amount, sender=alice) - - def test_transfer_event_fires(self, alice, bob, charlie, swap): - amount = swap.balanceOf(alice) - - swap.approve(bob, amount, sender=alice) - _, events = call_returning_result_and_logs(swap, "transferFrom", alice, charlie, amount, sender=bob) - - assert len(events) == 1 - assert repr(events[0]) == f"Transfer(sender={alice}, receiver={charlie}, value={amount})" diff --git a/tests/test_get_D.py b/tests/token/test_get_D.py similarity index 99% rename from tests/test_get_D.py rename to tests/token/test_get_D.py index 999c0fe0..422fd8d8 100644 --- a/tests/test_get_D.py +++ b/tests/token/test_get_D.py @@ -4,7 +4,6 @@ @pytest.fixture(scope="module") def new_math(): - return boa.loads( """ A_PRECISION: constant(uint256) = 100 diff --git a/tests/token/test_token_approve.py b/tests/token/test_token_approve.py new file mode 100644 index 00000000..12dfb96b --- /dev/null +++ b/tests/token/test_token_approve.py @@ -0,0 +1,156 @@ +import boa +import pytest +from eip712 import EIP712Message +from eth_account._utils.signing import to_bytes32 + +from tests.utils.transactions import call_returning_result_and_logs + + +@pytest.mark.parametrize("idx", range(4)) +def test_initial_approval_is_zero(swap, alice, accounts, idx, set_metapool_implementations): + assert swap.allowance(alice, accounts[idx]) == 0 + + +def test_approve(swap, alice, bob): + swap.approve(bob, 10**19, sender=alice) + assert swap.allowance(alice, bob) == 10**19 + + +def test_modify_approve_zero_nonzero(swap, alice, bob): + with boa.env.prank(alice): + swap.approve(bob, 10**19) + swap.approve(bob, 0) + swap.approve(bob, 12345678) + + assert swap.allowance(alice, bob) == 12345678 + + +def test_revoke_approve(swap, alice, bob): + with boa.env.prank(alice): + swap.approve(bob, 10**19) + swap.approve(bob, 0) + + assert swap.allowance(alice, bob) == 0 + + +def test_approve_self(swap, alice): + swap.approve(alice, 10**19, sender=alice) + assert swap.allowance(alice, alice) == 10**19 + + +def test_only_affects_target(swap, alice, bob): + swap.approve(bob, 10**19, sender=alice) + assert swap.allowance(bob, alice) == 0 + + +def test_returns_true(swap, alice, bob): + tx = swap.approve(bob, 10**19, sender=alice) + assert tx is True + + +def test_approval_event_fires(alice, bob, swap): + value = 10**19 + res, events = call_returning_result_and_logs(swap, "approve", bob, value, sender=alice) + + assert res is True + assert len(events) == 1 + assert repr(events[0]) == f"Approval(owner={alice}, spender={bob}, value={value})" + + +def test_infinite_approval(initial_setup, swap, alice, bob): + swap.approve(bob, 2**256 - 1, sender=alice) + swap.transferFrom(alice, bob, 10**18, sender=bob) + assert swap.allowance(alice, bob) == 2**256 - 1 + + +def permit_class(swap) -> type[EIP712Message]: + class Permit(EIP712Message): + # EIP-712 Domain Fields + _name_: "string" = swap.name() # noqa: F821 + _version_: "string" = swap.version() # noqa: F821 + _chainId_: "uint256" = boa.env.chain.chain_id # noqa: F821 + _verifyingContract_: "address" = swap.address # noqa: F821 + _salt_: "bytes32" = swap.salt() # noqa: F821 + + # EIP-2612 Data Fields + owner: "address" # noqa: F821 + spender: "address" # noqa: F821 + value: "uint256" # noqa: F821 + nonce: "uint256" # noqa: F821 + deadline: "uint256" = 2**256 - 1 # noqa: F821 + + return Permit + + +def test_permit(eth_acc, bob, swap): + value = 2**256 - 1 + permit = permit_class(swap)(owner=eth_acc.address, spender=bob, value=value, nonce=0) + sig = eth_acc.sign_message(permit.signable_message) + + res, events = call_returning_result_and_logs( + swap, + "permit", + eth_acc.address, + bob, + 2**256 - 1, + 2**256 - 1, + sig.v, + to_bytes32(sig.r), + to_bytes32(sig.s), + sender=bob, + ) + + assert swap.allowance(eth_acc.address, bob) == 2**256 - 1 + assert res is True + assert len(events) == 1 + assert repr(events[0]) == f"Approval(owner={eth_acc.address}, spender={bob}, value={value})" + assert swap.nonces(eth_acc.address) == 1 + + +def test_permit_contract(eth_acc, bob, swap): + # based on https://eips.ethereum.org/EIPS/eip-1271 + src = """ + # pragma version 0.3.10 + OWNER: public(immutable(address)) + + @external + def __init__(): + OWNER = msg.sender + + @view + @external + def isValidSignature(_hash: bytes32, _signature: Bytes[65]) -> bytes32: + signer: address = self._recover_signer(_hash, _signature) + if signer == OWNER: + return 0x1626ba7e00000000000000000000000000000000000000000000000000000000 + return 0xffffffff00000000000000000000000000000000000000000000000000000000 + + @view + @internal + def _recover_signer(_hash: bytes32, _signature: Bytes[65]) -> address: + v: uint256 = convert(slice(_signature, 64, 1), uint256) + r: uint256 = convert(slice(_signature, 0, 32), uint256) + s: uint256 = convert(slice(_signature, 32, 32), uint256) + return ecrecover(_hash, v, r, s) + """ + with boa.env.prank(eth_acc.address): + mock_contract = boa.loads(src) + + permit = permit_class(swap)(owner=mock_contract.address, spender=bob, value=2**256 - 1, nonce=0) + sig = eth_acc.sign_message(permit.signable_message) + + res, events = call_returning_result_and_logs( + swap, + "permit", + mock_contract.address, + bob, + 2**256 - 1, + 2**256 - 1, + sig.v, + to_bytes32(sig.r), + to_bytes32(sig.s), + sender=bob, + ) + assert swap.allowance(mock_contract.address, bob) == 2**256 - 1 + assert res is True + assert len(events) == 1 diff --git a/tests/token/test_token_transfer.py b/tests/token/test_token_transfer.py new file mode 100644 index 00000000..2e1d6585 --- /dev/null +++ b/tests/token/test_token_transfer.py @@ -0,0 +1,87 @@ +import boa +import pytest + +from tests.utils.transactions import call_returning_result_and_logs + + +@pytest.fixture(autouse=True) +def added_liquidity(initial_setup): + ... + + +def test_sender_balance_decreases(alice, bob, swap): + sender_balance = swap.balanceOf(alice) + amount = sender_balance // 4 + + swap.transfer(bob, amount, sender=alice) + + assert swap.balanceOf(alice) == sender_balance - amount + + +def test_receiver_balance_increases(alice, bob, swap): + receiver_balance = swap.balanceOf(bob) + amount = swap.balanceOf(alice) // 4 + + swap.transfer(bob, amount, sender=alice) + + assert swap.balanceOf(bob) == receiver_balance + amount + + +def test_total_supply_not_affected(alice, bob, swap): + total_supply = swap.totalSupply() + amount = swap.balanceOf(alice) + + swap.transfer(bob, amount, sender=alice) + + assert swap.totalSupply() == total_supply + + +def test_returns_true(alice, bob, swap): + amount = swap.balanceOf(alice) + res = swap.transfer(bob, amount, sender=alice) + + assert res is True + + +def test_transfer_full_balance(alice, bob, swap): + amount = swap.balanceOf(alice) + receiver_balance = swap.balanceOf(bob) + + swap.transfer(bob, amount, sender=alice) + + assert swap.balanceOf(alice) == 0 + assert swap.balanceOf(bob) == receiver_balance + amount + + +def test_transfer_zero_tokens(alice, bob, swap): + sender_balance = swap.balanceOf(alice) + receiver_balance = swap.balanceOf(bob) + + swap.transfer(bob, 0, sender=alice) + + assert swap.balanceOf(alice) == sender_balance + assert swap.balanceOf(bob) == receiver_balance + + +def test_transfer_to_self(alice, bob, swap): + sender_balance = swap.balanceOf(alice) + amount = sender_balance // 4 + + swap.transfer(alice, amount, sender=alice) + + assert swap.balanceOf(alice) == sender_balance + + +def test_insufficient_balance(alice, bob, swap): + balance = swap.balanceOf(alice) + + with boa.reverts(): + swap.transfer(bob, balance + 1, sender=alice) + + +def test_transfer_event_fires(alice, bob, swap): + amount = swap.balanceOf(alice) + _, events = call_returning_result_and_logs(swap, "transfer", bob, amount, sender=alice) + + assert len(events) == 1 + assert repr(events[0]) == f"Transfer(sender={alice}, receiver={bob}, value={amount})" diff --git a/tests/token/test_token_transfer_from.py b/tests/token/test_token_transfer_from.py new file mode 100644 index 00000000..6505852f --- /dev/null +++ b/tests/token/test_token_transfer_from.py @@ -0,0 +1,171 @@ +import boa +import pytest + +from tests.utils.transactions import call_returning_result_and_logs + + +@pytest.fixture(autouse=True) +def added_liquidity(initial_setup): + ... + + +def test_sender_balance_decreases(alice, bob, charlie, swap): + sender_balance = swap.balanceOf(alice) + amount = sender_balance // 4 + + swap.approve(bob, amount, sender=alice) + swap.transferFrom(alice, charlie, amount, sender=bob) + + assert swap.balanceOf(alice) == sender_balance - amount + + +def test_receiver_balance_increases(alice, bob, charlie, swap): + receiver_balance = swap.balanceOf(charlie) + amount = swap.balanceOf(alice) // 4 + + swap.approve(bob, amount, sender=alice) + swap.transferFrom(alice, charlie, amount, sender=bob) + + assert swap.balanceOf(charlie) == receiver_balance + amount + + +def test_caller_balance_not_affected(alice, bob, charlie, swap): + caller_balance = swap.balanceOf(bob) + amount = swap.balanceOf(alice) + + swap.approve(bob, amount, sender=alice) + swap.transferFrom(alice, charlie, amount, sender=bob) + + assert swap.balanceOf(bob) == caller_balance + + +def test_caller_approval_affected(alice, bob, charlie, swap): + approval_amount = swap.balanceOf(alice) + transfer_amount = approval_amount // 4 + + swap.approve(bob, approval_amount, sender=alice) + swap.transferFrom(alice, charlie, transfer_amount, sender=bob) + + assert swap.allowance(alice, bob) == approval_amount - transfer_amount + + +def test_receiver_approval_not_affected(alice, bob, charlie, swap): + approval_amount = swap.balanceOf(alice) + transfer_amount = approval_amount // 4 + + swap.approve(bob, approval_amount, sender=alice) + swap.approve(charlie, approval_amount, sender=alice) + swap.transferFrom(alice, charlie, transfer_amount, sender=bob) + + assert swap.allowance(alice, charlie) == approval_amount + + +def test_total_supply_not_affected(alice, bob, charlie, swap): + total_supply = swap.totalSupply() + amount = swap.balanceOf(alice) + + swap.approve(bob, amount, sender=alice) + swap.transferFrom(alice, charlie, amount, sender=bob) + + assert swap.totalSupply() == total_supply + + +def test_returns_true(alice, bob, charlie, swap): + amount = swap.balanceOf(alice) + swap.approve(bob, amount, sender=alice) + res = swap.transferFrom(alice, charlie, amount, sender=bob) + + assert res is True + + +def test_transfer_full_balance(alice, bob, charlie, swap): + amount = swap.balanceOf(alice) + receiver_balance = swap.balanceOf(charlie) + + swap.approve(bob, amount, sender=alice) + swap.transferFrom(alice, charlie, amount, sender=bob) + + assert swap.balanceOf(alice) == 0 + assert swap.balanceOf(charlie) == receiver_balance + amount + + +def test_transfer_zero_tokens(alice, bob, charlie, swap): + sender_balance = swap.balanceOf(alice) + receiver_balance = swap.balanceOf(charlie) + + swap.approve(bob, sender_balance, sender=alice) + swap.transferFrom(alice, charlie, 0, sender=bob) + + assert swap.balanceOf(alice) == sender_balance + assert swap.balanceOf(charlie) == receiver_balance + + +def test_transfer_zero_tokens_without_approval(alice, bob, charlie, swap): + sender_balance = swap.balanceOf(alice) + receiver_balance = swap.balanceOf(charlie) + + swap.transferFrom(alice, charlie, 0, sender=bob) + + assert swap.balanceOf(alice) == sender_balance + assert swap.balanceOf(charlie) == receiver_balance + + +def test_insufficient_balance(alice, bob, charlie, swap): + balance = swap.balanceOf(alice) + + swap.approve(bob, balance + 1, sender=alice) + with boa.reverts(): + swap.transferFrom(alice, charlie, balance + 1, sender=bob) + + +def test_insufficient_approval(alice, bob, charlie, swap): + balance = swap.balanceOf(alice) + + swap.approve(bob, balance - 1, sender=alice) + with boa.reverts(): + swap.transferFrom(alice, charlie, balance, sender=bob) + + +def test_no_approval(alice, bob, charlie, swap): + balance = swap.balanceOf(alice) + + with boa.reverts(): + swap.transferFrom(alice, charlie, balance, sender=bob) + + +def test_revoked_approval(alice, bob, charlie, swap): + balance = swap.balanceOf(alice) + + swap.approve(bob, balance, sender=alice) + swap.approve(bob, 0, sender=alice) + + with boa.reverts(): + swap.transferFrom(alice, charlie, balance, sender=bob) + + +def test_transfer_to_self(alice, bob, swap): + sender_balance = swap.balanceOf(alice) + amount = sender_balance // 4 + + swap.approve(alice, sender_balance, sender=alice) + swap.transferFrom(alice, alice, amount, sender=alice) + + assert swap.balanceOf(alice) == sender_balance + assert swap.allowance(alice, alice) == sender_balance - amount + + +def test_transfer_to_self_no_approval(alice, bob, swap): + amount = swap.balanceOf(alice) + + with boa.reverts(): + swap.transferFrom(alice, alice, amount, sender=alice) + + +def test_transfer_event_fires(alice, bob, charlie, swap): + amount = swap.balanceOf(alice) + + swap.approve(bob, amount, sender=alice) + _, events = call_returning_result_and_logs(swap, "transferFrom", alice, charlie, amount, sender=bob) + + assert len(events) == 1 + assert repr(events[0]) == f"Transfer(sender={alice}, receiver={charlie}, value={amount})" diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index db30f6eb..bf970831 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -1,7 +1,7 @@ from math import log -def approx(x1: int, x2: int, precision: int, abs_precision=None): +def approx(x1: int, x2: int, precision: float, abs_precision=None): if precision >= 1: return True result = False @@ -17,7 +17,6 @@ def approx(x1: int, x2: int, precision: int, abs_precision=None): def get_asset_types_in_pool(pool): - if "asset_type" in pool._immutables.__dict__.keys(): return [pool._immutables.asset_type] return pool._immutables.asset_types