diff --git a/.github/workflows/release_win.yml b/.github/workflows/release_win.yml new file mode 100644 index 000000000..d08ac95a3 --- /dev/null +++ b/.github/workflows/release_win.yml @@ -0,0 +1,60 @@ +name: Release for Windows + +# This workflow is triggered on pushing a tag BE CAREFUL this application AUTO UPDATES !!! +# git tag vX.Y.Z +# git push origin tag vX.Y.Z + +on: [pull_request] + +jobs: + build-windows: + runs-on: windows-latest + #strategy: + # matrix: + # arch: [ x64, arm64 ] + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - uses: actions/setup-node@v4 + with: + node-version: lts/* + + - name: Install and configure Poetry + uses: snok/install-poetry@v1 + with: + # version: '1.4.0' + virtualenvs-create: true + virtualenvs-in-project: false + virtualenvs-path: ~/my-custom-path + installer-parallel: true + #- name: Setup tmate session + # uses: mxschmitt/action-tmate@v3 + - name: Install dependencies + run: poetry install + + - name: install node deps + run: yarn install-deps + + - name: set env vars to prod.env + env: + NODE_ENV: production + DEV_RPC: https://rpc-gate.autonolas.tech/gnosis-rpc/ + IS_STAGING: ${{ github.ref != 'refs/heads/main' && 'true' || 'false' }} + FORK_URL: https://rpc-gate.autonolas.tech/gnosis-rpc/ + GH_TOKEN: ${{ secrets.github_token}} + run: | + echo NODE_ENV=$NODE_ENV >> prod.env + echo DEV_RPC=$DEV_RPC >> prod.env + echo IS_STAGING=$IS_STAGING >> prod.env + echo FORK_URL=$FORK_URL >> prod.env + cat prod.env + - run: rm -rf /dist + - name: "Build, notarize, publish" + run: make build diff --git a/.gitleaksignore b/.gitleaksignore index 33c8c27cf..95964f4b2 100644 --- a/.gitleaksignore +++ b/.gitleaksignore @@ -29,4 +29,7 @@ d8149e9b5b7bd6a7ed7bc1039900702f1d4f287b:operate/services/manage.py:generic-api- 99c0f139b037da2587708212fcf6d0e20786d0ba:operate/services/manage.py:generic-api-key:455 91ec07457f69e9a29f63693ac8ef887e4b5f49f0:operate/services/manage.py:generic-api-key:454 410bea2bd02ff54da69387fe8f3b58793e09f7b0:operate/services/manage.py:generic-api-key:421 -410bea2bd02ff54da69387fe8f3b58793e09f7b0:operate/services/manage.py:generic-api-key:422 \ No newline at end of file +410bea2bd02ff54da69387fe8f3b58793e09f7b0:operate/services/manage.py:generic-api-key:422 +467e8e64f51fb3659e5af17ba53ab587ec24fc30:operate/services/manage.py:generic-api-key:290 +64afe2ea92daafa2515c054f0e09931622d99f31:operate/services/manage.py:generic-api-key:290 +64afe2ea92daafa2515c054f0e09931622d99f31:operate/services/manage.py:generic-api-key:289 \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..1afb34116 --- /dev/null +++ b/Makefile @@ -0,0 +1,52 @@ + +define setup_env + $(eval ENV_FILE := $(1).env) + @echo " - setup env $(ENV_FILE)" + $(eval include $(1).env) + $(eval export) +endef + + +./trader/: + pwd + git clone https://github.com/valory-xyz/trader.git + +./dist/aea_win.exe: ./trader/ + mkdir -p dist + cd trader && poetry install && poetry run pyinstaller --collect-data eth_account --collect-all aea --collect-all autonomy --collect-all operate --collect-all aea_ledger_ethereum --collect-all aea_ledger_cosmos --collect-all aea_ledger_ethereum_flashbots --hidden-import aea_ledger_ethereum --hidden-import aea_ledger_cosmos --hidden-import aea_ledger_ethereum_flashbots --hidden-import grpc --hidden-import openapi_core --collect-all google.protobuf --collect-all openapi_core --collect-all openapi_spec_validator --collect-all asn1crypto --hidden-import py_ecc --hidden-import pytz --onefile pyinstaller/trader_bin.py --name trader_win + cp -f trader/dist/trader_win.exe ./dist/aea_win.exe + pwd + + +./dist/tendermint_win.exe: ./operate + pwd + poetry install && poetry run pyinstaller operate/services/utils/tendermint.py --onefile --name tendermint_win + + +./dist/pearl_win.exe: ./dist/aea_win.exe ./dist/tendermint_win.exe + pwd + poetry install && poetry run pyinstaller --collect-data eth_account --collect-all aea --collect-all coincurve --collect-all autonomy --collect-all operate --collect-all aea_ledger_ethereum --collect-all aea_ledger_cosmos --collect-all aea_ledger_ethereum_flashbots --hidden-import aea_ledger_ethereum --hidden-import aea_ledger_cosmos --hidden-import aea_ledger_ethereum_flashbots operate/pearl.py --add-binary dist/aea_win.exe:. --add-binary dist/tendermint_win.exe:. --onefile --name pearl_win + + +.PHONY: operate +operate: ./dist/pearl_win.exe + +.PHONY: build +build: ./dist/pearl_win.exe + $(call setup_env, prod) + echo ${DEV_RPC} + mkdir -p ./electron/bins + cp -f dist/pearl_win.exe ./electron/bins/pearl_win.exe + echo ${NODE_ENV} + NODE_ENV=${NODE_ENV} DEV_RPC=${DEV_RPC} FORK_URL=${FORK_URL} yarn build:frontend + node build-win.js + + +.PHONY: build-tenderly +build-tenderly: ./dist/pearl_win.exe + $(call setup_env, dev-tenderly) + echo ${DEV_RPC} + cp -f dist/pearl_win.exe ./electron/bins/pearl_win.exe + echo ${NODE_ENV} + NODE_ENV=${NODE_ENV} DEV_RPC=${DEV_RPC} FORK_URL=${FORK_URL} yarn build:frontend + node build-win-tenderly.js \ No newline at end of file diff --git a/README.md b/README.md index 8eb3551aa..76b4ede77 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ Pearl is an application used to run autonomous agents powered by the OLAS Networ - Javascript / TypeScript - Python (3.10) - Poetry (^1.7.1) -- Docker Engine ## Getting Started @@ -26,7 +25,7 @@ The following installation steps assume you have the following on each OS:

NodeJS

-NodeJS is best installed and managed through NVM. It allows you to install and select specific versions of NodeJS. Pearl has been built using version 20.11, LTS. +NodeJS is best installed and managed through NVM. It allows you to install and select specific versions of NodeJS. Pearl has been built using version 20 LTS.
Linux
@@ -117,38 +116,6 @@ If promoted to run `pipx ensurepath`, run it.
-

Docker

- -
Linux
- -*Update the `ubuntu.22.04~jammy` version string to your current OS version before running the following command:* - -```bash -VERSION_STRING=5:24.0.7-1~ubuntu.22.04~jammy -sudo apt-get install docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io docker-buildx-plugin docker-compose-plugin -sudo usermod -aG docker $USER -``` - -If you are unsure about your current OS version/codename, you can find it by running: - -```bash -lsb_release -a -``` - -
MacOS
- -You can [install Docker Desktop via the Docker website](https://www.docker.com/products/docker-desktop/). Be sure to select the correct version for your system's CPU architecture. - -If you are unsure about your system's CPU architecture, run the following command: - -```bash -uname -p -# x86 64 Intel chip -# arm64 Apple chip -``` - -
-

Setting up your .env file

Create an `.env` file in the root directory, or rename `.env.example` to `.env`. @@ -202,7 +169,7 @@ Provided your system dependencies are installed, environment variables are set, You can start Pearl by running the following command in the root directory: ```bash -yarn start +yarn dev ``` This will run Electron, which launches the NextJS frontend and the Python backend as child processes. @@ -254,9 +221,4 @@ poetry run python scripts/fund.py 0xYOURADDRESS poetry run python scripts/transfer_olas.py PATH_TO_KEY_CONTAINING_OLAS ADDRESS_TO_TRANSFER AMOUNT ``` - - -

Notes and Common Issues

- -- If Pearl is running, it will kill any attempt to run another Pearl instance. This is to ensure there are no port conflicts. -- Enivironment variables are cached in the terminal, if you change them while your terminal is open, you will need to restart the terminal. \ No newline at end of file + \ No newline at end of file diff --git a/build-win-tenderly.js b/build-win-tenderly.js new file mode 100644 index 000000000..68fbdbbf4 --- /dev/null +++ b/build-win-tenderly.js @@ -0,0 +1,38 @@ +/** + * This script is used to build the electron app **with notarization**. It is used for the final build and release process. + */ +require('dotenv').config(); +const build = require('electron-builder').build; + +const { publishOptions } = require('./electron/constants'); + +const main = async () => { + console.log('Building...'); + + /** @type import {CliOptions} from "electron-builder" */ + await build({ + publish: 'onTag', + config: { + appId: 'xyz.valory.olas-operate-app', + artifactName: '${productName}-${version}-${platform}-${arch}-tenderly.${ext}', + productName: 'Pearl', + files: ['electron/**/*', 'package.json'], + directories: { + output: 'dist', + }, + nsis: { + oneClick: false, + }, + extraResources: [ + { + from: 'electron/bins', + to: 'bins', + filter: ['**/*'], + }, + ], + + }, + }); +}; + +main().then((response) => { console.log('Build & Notarize complete'); }).catch((e) => console.error(e)); diff --git a/build-win.js b/build-win.js new file mode 100644 index 000000000..8575e448a --- /dev/null +++ b/build-win.js @@ -0,0 +1,48 @@ +/** + * This script is used to build the electron app **with notarization**. It is used for the final build and release process. + */ +require('dotenv').config(); +const build = require('electron-builder').build; + +const { publishOptions } = require('./electron/constants'); + + +function artifactName() { + const env = process.env.NODE_ENV; + const prefix = env === 'production' ? '' : 'dev-'; + return prefix + '${productName}-${version}-${platform}-${arch}.${ext}'; +} + +const main = async () => { + console.log('Building...'); + + /** @type import {CliOptions} from "electron-builder" */ + await build({ + publish: 'onTag', + config: { + appId: 'xyz.valory.olas-operate-app', + artifactName: artifactName(), + productName: 'Pearl', + files: ['electron/**/*', 'package.json'], + directories: { + output: 'dist', + }, + nsis: { + oneClick: false, + }, + publish: publishOptions, + category: 'public.app-category.utilities', + icon: 'electron/assets/icons/splash-robot-head-dock.png', + extraResources: [ + { + from: 'electron/bins', + to: 'bins', + filter: ['**/*'], + }, + ], + + }, + }); +}; + +main().then((response) => { console.log('Build & Notarize complete'); }).catch((e) => console.error(e)); diff --git a/electron/install.js b/electron/install.js index 2c3de2faa..6e4cf4807 100644 --- a/electron/install.js +++ b/electron/install.js @@ -6,15 +6,15 @@ const process = require('process'); const axios = require('axios'); const { spawnSync } = require('child_process'); const { logger } = require('./logger'); - +const { execSync} = require('child_process'); const { paths } = require('./constants'); - +const homedir = os.homedir(); /** * current version of the pearl release * - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26" * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ -const OlasMiddlewareVersion = '0.1.0rc115'; +const OlasMiddlewareVersion = '0.1.0rc120'; const path = require('path'); const { app } = require('electron'); @@ -55,6 +55,21 @@ const TendermintUrls = { }, }; + +function execSyncExitCode(cmd) { + try { + execSync(cmd); + return 0; + } + catch (error) { + logger.electron(error.status); // Might be 127 in your example. + logger.electron(error.message); // Holds the message you typically want. + logger.electron(error.stderr.toString()); // Holds the stderr output. Use `.toString()`. + logger.electron(error.stdout.toString()); // Holds the stdout output. Use `.toString()`. + return error.status; + } +} + function getBinPath(command) { return spawnSync('/usr/bin/which', [command], { env: Env }) .stdout?.toString() @@ -79,6 +94,7 @@ function runCmdUnix(command, options) { logger.electron(`===== stderr ===== \n${output.stderr}`); } + function runSudoUnix(command, options) { let bin = getBinPath(command); if (!bin) { @@ -113,6 +129,12 @@ function isTendermintInstalledUnix() { return Boolean(getBinPath('tendermint')); } +function isTendermintInstalledWindows() { + return true; + //always installed cause bundled in + return execSyncExitCode('tendermint --help') === 0; +} + async function downloadFile(url, dest) { const writer = fs.createWriteStream(dest); try { @@ -132,6 +154,41 @@ async function downloadFile(url, dest) { } } +async function installTendermintWindows() { + return; + // bundled in + logger.electron(`Installing tendermint for ${os.platform()}-${process.arch}`); + const cwd = process.cwd(); + process.chdir(paths.tempDir); + + const url = TendermintUrls[os.platform()][process.arch]; + + logger.electron( + `Downloading ${url} to ${paths.tempDir}. This might take a while...`, + ); + await downloadFile(url, `${paths.tempDir}/tendermint.tar.gz`); + + logger.electron(`Installing tendermint binary`); + try { + execSync('tar -xvf tendermint.tar.gz'); + } catch (error){ + logger.electron(error.status); // Might be 127 in your example. + logger.electron(error.message); // Holds the message you typically want. + logger.electron(error.stderr.toString()); // Holds the stderr output. Use `.toString()`. + logger.electron(error.stdout.toString()); // Holds the stdout output. Use `.toString()`. + } + + const bin_dir = homedir + "//AppData//Local//Microsoft//WindowsApps//" + if (!Env.CI) { + if (!fs.existsSync(bin_dir)) { + fs.mkdirSync(bin_dir, {recursive: true}); + } + fs.copyFileSync("tendermint.exe", bin_dir + "tendermint.exe"); + } + process.chdir(cwd); +} + + async function installTendermintUnix() { logger.electron(`Installing tendermint for ${os.platform()}-${process.arch}`); const cwd = process.cwd(); @@ -202,8 +259,24 @@ async function setupUbuntu(ipcChannel) { } } + + +async function setupWindows(ipcChannel) { + logger.electron('Creating required directories'); + await createDirectory(`${paths.dotOperateDirectory}`); + await createDirectory(`${paths.tempDir}`); + + logger.electron('Checking tendermint installation: ' + isTendermintInstalledWindows()); + if (!isTendermintInstalledWindows()) { + ipcChannel.send('response', 'Installing tendermint'); + logger.electron('Installing tendermint'); + await installTendermintWindows(); + } +} + module.exports = { setupDarwin, setupUbuntu, + setupWindows, Env, }; diff --git a/electron/main.js b/electron/main.js index e60d56fd1..a1035a227 100644 --- a/electron/main.js +++ b/electron/main.js @@ -17,7 +17,7 @@ const http = require('http'); const AdmZip = require('adm-zip'); const { TRAY_ICONS, TRAY_ICONS_PATHS } = require('./icons'); -const { setupDarwin, setupUbuntu, Env } = require('./install'); +const { setupDarwin, setupUbuntu, setupWindows, Env } = require('./install'); const { paths } = require('./constants'); const { killProcesses } = require('./processes'); @@ -39,6 +39,9 @@ const binaryPaths = { arm64: 'bins/pearl_arm64', x64: 'bins/pearl_x64', }, + win32: { + x64: 'bins/pearl_win.exe', + }, }; let appConfig = { @@ -334,6 +337,7 @@ async function launchDaemon() { } async function launchDaemonDev() { + const check = new Promise(function (resolve, _reject) { operateDaemon = spawn('poetry', [ 'run', @@ -398,6 +402,7 @@ async function launchNextAppDev() { 'yarn', ['dev:frontend', '--port', appConfig.ports.dev.next], { + shell: true, env: { ...process.env, NEXT_PUBLIC_BACKEND_PORT: appConfig.ports.dev.operate, @@ -441,7 +446,7 @@ ipcMain.on('check', async function (event, _argument) { if (platform === 'darwin') { await setupDarwin(event.sender); } else if (platform === 'win32') { - // TODO + await setupWindows(event.sender); } else { await setupUbuntu(event.sender); } diff --git a/electron/processes.js b/electron/processes.js index e67dcaac5..faaa9266f 100644 --- a/electron/processes.js +++ b/electron/processes.js @@ -3,7 +3,7 @@ const { exec } = require('child_process'); const unixKillCommand = 'kill -9'; const windowsKillCommand = 'taskkill /F /PID'; - +const { logger } = require('./logger'); const isWindows = process.platform === 'win32'; function killProcesses(pid) { @@ -16,23 +16,29 @@ function killProcesses(pid) { // Array of PIDs to kill, starting with the children const pidsToKill = children.map((p) => p.PID); - pidsToKill.push(pid); // Also kill the main process + logger.info("Pids to kill " + JSON.stringify(pidsToKill)); const killCommand = isWindows ? windowsKillCommand : unixKillCommand; - const joinedCommand = pidsToKill - .map((pid) => `${killCommand} ${pid}`) - .join('; '); // Separate commands with a semicolon, so they run in sequence even if one fails. Also works on Windows. - - exec(joinedCommand, (err) => { - if ( - err?.message?.includes(isWindows ? 'not found' : 'No such process') - ) { - return; // Ignore errors for processes that are already dead - } - reject(err); - }); - resolve(); + let errors = []; + for (const ppid of pidsToKill) { + logger.info("kill: " + ppid); + exec(`${killCommand} ${ppid}`, (err) => { + logger.error("Pids to kill error:" + err); + if ( + err?.message?.includes(isWindows ? 'not found' : 'No such process') + ) { + return; // Ignore errors for processes that are already dead + } + errors.push(err); + }); + } + + if (errors.length === 0) { + reject(errors); + + + } else resolve(); }); }); } diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index 97bf85641..ad3e17053 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -18,7 +18,6 @@ import styled from 'styled-components'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { COW_SWAP_GNOSIS_XDAI_OLAS_URL } from '@/constants/urls'; import { useWallet } from '@/hooks/useWallet'; -import { Address } from '@/types/Address'; import { copyToClipboard } from '@/utils/copyToClipboard'; import { truncateAddress } from '@/utils/truncate'; @@ -35,23 +34,6 @@ const CustomizedCardSection = styled(CardSection)<{ border?: boolean }>` export const AddFundsSection = () => { const [isAddFundsVisible, setIsAddFundsVisible] = useState(false); - const { masterSafeAddress } = useWallet(); - - const fundingAddress: Address | undefined = masterSafeAddress; - - const truncatedFundingAddress: string | undefined = useMemo( - () => fundingAddress && truncateAddress(fundingAddress), - [fundingAddress], - ); - - const handleCopyAddress = useCallback( - () => - fundingAddress && - copyToClipboard(fundingAddress).then(() => - message.success('Copied successfully!'), - ), - [fundingAddress], - ); return ( <> @@ -75,17 +57,36 @@ export const AddFundsSection = () => { - {isAddFundsVisible && ( - <> - - - - - )} + {isAddFundsVisible && } + + ); +}; + +export const OpenAddFundsSection = () => { + const { masterSafeAddress } = useWallet(); + + const truncatedFundingAddress: string | undefined = useMemo( + () => masterSafeAddress && truncateAddress(masterSafeAddress), + [masterSafeAddress], + ); + + const handleCopyAddress = useCallback( + () => + masterSafeAddress && + copyToClipboard(masterSafeAddress).then(() => + message.success('Copied successfully!'), + ), + [masterSafeAddress], + ); + return ( + <> + + + ); }; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx b/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx index f2c1cf6cd..7df340884 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx @@ -6,28 +6,35 @@ import { UNICODE_SYMBOLS } from '@/constants/symbols'; const { Text } = Typography; export const AlertInsufficientMigrationFunds = ({ - totalOlasBalance, + masterSafeOlasBalance, + stakedOlasBalance, + totalOlasRequiredForStaking, }: { - totalOlasBalance: number; -}) => ( - - - Insufficient amount of funds to switch - + masterSafeOlasBalance: number; + stakedOlasBalance: number; + totalOlasRequiredForStaking: number; +}) => { + const requiredOlasDeposit = + totalOlasRequiredForStaking - (stakedOlasBalance + masterSafeOlasBalance); - Add funds to your account to meet the program requirements. - - Your current OLAS balance:{' '} - {totalOlasBalance} OLAS - - - } - /> -); + return ( + + + An additional {requiredOlasDeposit} OLAS is required to switch + + + Add {requiredOlasDeposit} OLAS to your account to + meet the contract requirements and switch. + + + } + /> + ); +}; export const AlertNoSlots = () => ( { const { goto } = usePageState(); - const { setServiceStatus, serviceStatus, setIsServicePollingPaused } = - useServices(); + const { + setServiceStatus, + serviceStatus, + setIsServicePollingPaused, + updateServiceStatus, + } = useServices(); const { serviceTemplate } = useServiceTemplates(); const { setMigrationModalOpen } = useModals(); const { activeStakingProgram, defaultStakingProgram, updateStakingProgram } = useStakingProgram(); - const { stakingContractInfoRecord } = useStakingContractInfo(); const { token } = useToken(); - const { totalOlasBalance, isBalanceLoaded } = useBalance(); - const { isServiceStakedForMinimumDuration } = useStakingContractInfo(); + const { safeBalance, totalOlasStakedBalance, isBalanceLoaded } = useBalance(); + const { isServiceStakedForMinimumDuration, stakingContractInfoRecord } = + useStakingContractInfo(); + const [isFundingSectionOpen, setIsFundingSectionOpen] = useState(false); + + const stakingContractAddress = + SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS][ + stakingProgram + ]; const stakingContractInfoForStakingProgram = stakingContractInfoRecord?.[stakingProgram]; @@ -87,10 +96,15 @@ export const StakingContractSection = ({ ); const hasEnoughOlasToMigrate = useMemo(() => { - if (totalOlasBalance === undefined) return false; - if (!minimumOlasRequiredToMigrate) return false; - return totalOlasBalance >= minimumOlasRequiredToMigrate; - }, [minimumOlasRequiredToMigrate, totalOlasBalance]); + if (safeBalance?.OLAS === undefined || totalOlasStakedBalance === undefined) + return false; + + const balanceForMigration = safeBalance.OLAS + totalOlasStakedBalance; + + if (minimumOlasRequiredToMigrate === undefined) return false; + + return balanceForMigration >= minimumOlasRequiredToMigrate; + }, [minimumOlasRequiredToMigrate, safeBalance?.OLAS, totalOlasStakedBalance]); const hasEnoughSlots = stakingContractInfoForStakingProgram?.maxNumServices && @@ -167,6 +181,7 @@ export const StakingContractSection = ({ isBalanceLoaded, isSelected, isServiceStakedForMinimumDuration, + minimumOlasRequiredToMigrate, serviceStatus, ]); @@ -179,9 +194,17 @@ export const StakingContractSection = ({ return ; } - if (!hasEnoughOlasToMigrate) { + if ( + !hasEnoughOlasToMigrate && + safeBalance?.OLAS !== undefined && + totalOlasStakedBalance !== undefined + ) { return ( - + ); } @@ -191,10 +214,12 @@ export const StakingContractSection = ({ }, [ isSelected, isBalanceLoaded, - totalOlasBalance, hasEnoughSlots, hasEnoughOlasToMigrate, isAppVersionCompatible, + safeBalance?.OLAS, + totalOlasStakedBalance, + minimumOlasRequiredToMigrate, ]); const contractTagStatus = useMemo(() => { @@ -213,40 +238,41 @@ export const StakingContractSection = ({ }, [activeStakingProgram, defaultStakingProgram, stakingProgram]); return ( - - {/* Title */} - - {`${activeStakingProgramMeta.name} contract`} - {/* TODO: pass `status` attribute */} - - {!isSelected && ( - // here instead of isSelected we should check that the contract is not the old staking contract - // but the one from staking factory (if we want to open govern) - - Contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} - - )} - - - {/* TODO: fix */} - - {/* Contract details + <> + + {/* Title */} + + {`${activeStakingProgramMeta.name} contract`} + + {!isSelected && ( + // here instead of isSelected we should check that the contract is not the old staking contract + // but the one from staking factory (if we want to open govern) + + Contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} + + )} + + + {/* TODO: redisplay once bugs resolved */} + + {/* Contract details {stakingContractInfo?.availableRewards && ( )} */} - {cantMigrateAlert} - {/* Switch to program button */} - {!isSelected && ( - + {cantMigrateAlert} + {/* Switch to program button */} + {stakingProgram !== StakingProgram.Alpha && ( + + + + )} + {stakingProgram === StakingProgram.Beta && ( - + )} + + {stakingProgram === StakingProgram.Beta && isFundingSectionOpen && ( + )} - + ); }; diff --git a/frontend/components/ManageStakingPage/index.tsx b/frontend/components/ManageStakingPage/index.tsx index 310d19eca..82938256f 100644 --- a/frontend/components/ManageStakingPage/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -1,8 +1,6 @@ import { CloseOutlined } from '@ant-design/icons'; import { Button, Card } from 'antd'; -import { Chain } from '@/client'; -import { SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES } from '@/constants/contractAddresses'; import { Pages } from '@/enums/PageState'; import { StakingProgram } from '@/enums/StakingProgram'; import { usePageState } from '@/hooks/usePageState'; @@ -26,15 +24,8 @@ export const ManageStakingPage = () => { } > - {Object.entries( - SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS], - ).map(([stakingProgram, contractAddress]) => ( - - ))} + + ); }; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 19948f76a..3002a9736 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -4,7 +4,7 @@ import { StakingProgram } from '@/enums/StakingProgram'; export const SERVICE_TEMPLATES: ServiceTemplate[] = [ { name: 'Trader Agent', - hash: 'bafybeicrstlxew36hlxl7pzi73nmd44aibnhwxzkchzlec6t6yhvs7gvhy', + hash: 'bafybeihqtqgohejyebrb4jvd2fgccuasmqk3gc456ylyfa7tcn6rucdrxm', // hash: 'bafybeibbloa4w33vj4bvdkso7pzk6tr3duvxjpecbx4mur4ix6ehnwb5uu', // temporary description: 'Trader agent for omen prediction markets', image: diff --git a/frontend/package.json b/frontend/package.json index ec20ee33a..0289f79d7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -45,7 +45,7 @@ "private": true, "scripts": { "dev": "next dev", - "build": "NODE_ENV=production next build", + "build": "bash -c \"DEV_RPC=$DEV_RPC FORK_URL=$FORK_URL NODE_ENV=production next build\"", "lint": "next lint", "test": "jest", "start": "next start" diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 42657f818..9227cb596 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -28,19 +28,19 @@ export default function App({ Component, pageProps }: AppProps) { }, []); return ( - - - - - - - - - - - - - + + + + + + + + + + + + + {isMounted ? ( @@ -50,18 +50,18 @@ export default function App({ Component, pageProps }: AppProps) { ) : null} - - - - - - - - - - - - - + + + + + + + + + + + + + ); } diff --git a/operate/cli.py b/operate/cli.py index 7d5285d13..2c491ad3b 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -143,17 +143,22 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st home: t.Optional[Path] = None, ) -> FastAPI: """Create FastAPI object.""" + HEALTH_CHECKER_OFF = os.environ.get("HEALTH_CHECKER_OFF", "0") == "1" + number_of_fails = int(os.environ.get("HEALTH_CHECKER_TRIES", "5")) logger = setup_logger(name="operate") + if HEALTH_CHECKER_OFF: + logger.warning("healthchecker is off!!!") operate = OperateApp(home=home, logger=logger) funding_jobs: t.Dict[str, asyncio.Task] = {} - health_checker = HealthChecker(operate.service_manager()) + health_checker = HealthChecker( + operate.service_manager(), number_of_fails=number_of_fails + ) # Create shutdown endpoint shutdown_endpoint = uuid.uuid4().hex (operate._path / "operate.kill").write_text( # pylint: disable=protected-access shutdown_endpoint ) - thread_pool_executor = ThreadPoolExecutor() async def run_in_executor(fn: t.Callable, *args: t.Any) -> t.Any: @@ -188,7 +193,9 @@ def schedule_healthcheck_job( service: str, ) -> None: """Schedule a healthcheck job.""" - health_checker.start_for_service(service) + if not HEALTH_CHECKER_OFF: + # dont start health checker if it's switched off + health_checker.start_for_service(service) def cancel_funding_job(service: str) -> None: """Cancel funding job.""" @@ -530,8 +537,8 @@ async def _create_services(request: Request) -> JSONResponse: if template.get("deploy", False): def _fn() -> None: + # deploy_service_onchain_from_safe includes stake_service_on_chain_from_safe manager.deploy_service_onchain_from_safe(hash=service.hash) - # manager.stake_service_on_chain_from_safe(hash=service.hash) # Done inside deploy_service_onchain manager.fund_service(hash=service.hash) manager.deploy_service_locally(hash=service.hash) @@ -556,8 +563,9 @@ async def _update_services(request: Request) -> JSONResponse: ) if template.get("deploy", False): manager = operate.service_manager() + + # deploy_service_onchain_from_safe includes stake_service_on_chain_from_safe manager.deploy_service_onchain_from_safe(hash=service.hash) - # manager.stake_service_on_chain_from_safe(hash=service.hash) # Done in deploy_service_onchain_from_safe manager.fund_service(hash=service.hash) manager.deploy_service_locally(hash=service.hash) schedule_funding_job(service=service.hash) @@ -675,7 +683,7 @@ async def _start_service_locally(request: Request) -> JSONResponse: def _fn() -> None: manager.deploy_service_onchain(hash=service) - # manager.stake_service_on_chain(hash=service) + manager.stake_service_on_chain(hash=service) manager.fund_service(hash=service) manager.deploy_service_locally(hash=service, force=True) diff --git a/operate/ledger/__init__.py b/operate/ledger/__init__.py index 078a93d1e..c54609833 100644 --- a/operate/ledger/__init__.py +++ b/operate/ledger/__init__.py @@ -38,6 +38,7 @@ GOERLI_RPC = os.environ.get("DEV_RPC", "https://ethereum-goerli.publicnode.com") SOLANA_RPC = os.environ.get("DEV_RPC", "https://api.mainnet-beta.solana.com") + PUBLIC_RPCS = { ChainType.ETHEREUM: ETHEREUM_PUBLIC_RPC, ChainType.GNOSIS: GNOSIS_PUBLIC_RPC, diff --git a/operate/services/deployment_runner.py b/operate/services/deployment_runner.py index 1bf81904e..79c8940dc 100644 --- a/operate/services/deployment_runner.py +++ b/operate/services/deployment_runner.py @@ -22,7 +22,6 @@ import os import platform import shutil # nosec -import signal # nosec import subprocess # nosec import sys # nosec import time @@ -55,7 +54,6 @@ def stop(self) -> None: def _kill_process(pid: int) -> None: """Kill process.""" - print(f"Trying to kill process: {pid}") while True: if not psutil.pid_exists(pid=pid): return @@ -66,14 +64,7 @@ def _kill_process(pid: int) -> None: ): return try: - os.kill( - pid, - ( - signal.CTRL_C_EVENT # type: ignore - if platform.platform() == "Windows" - else signal.SIGKILL - ), - ) + process.kill() except OSError: return time.sleep(1) @@ -243,7 +234,7 @@ def _start_agent(self) -> None: stderr=subprocess.DEVNULL, env={**os.environ, **env}, creationflags=( - 0x00000008 if platform.system() == "Windows" else 0 + 0x00000200 if platform.system() == "Windows" else 0 ), # Detach process from the main process ) (working_dir / "agent.pid").write_text( @@ -261,9 +252,13 @@ def _start_tendermint(self) -> None: cwd=working_dir, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, - env={**os.environ, **env}, + env={ + **os.environ, + **env, + "PATH": os.environ["PATH"] + ";" + os.path.dirname(sys.executable), + }, creationflags=( - 0x00000008 if platform.system() == "Windows" else 0 + 0x00000200 if platform.system() == "Windows" else 0 ), # Detach process from the main process ) (working_dir / "tendermint.pid").write_text( @@ -272,6 +267,25 @@ def _start_tendermint(self) -> None: ) +class PyInstallerHostDeploymentRunnerMac(PyInstallerHostDeploymentRunner): + """Mac deployment runner.""" + + +class PyInstallerHostDeploymentRunnerWindows(PyInstallerHostDeploymentRunner): + """Windows deployment runner.""" + + @property + def _aea_bin(self) -> str: + """Return aea_bin path.""" + abin = str(Path(sys._MEIPASS) / "aea_win.exe") # type: ignore # pylint: disable=protected-access + return abin + + @property + def _tendermint_bin(self) -> str: + """Return tendermint path.""" + return str(Path(sys._MEIPASS) / "tendermint_win.exe") # type: ignore # pylint: disable=protected-access + + class HostPythonHostDeploymentRunner(BaseDeploymentRunner): """Deployment runner for host installed python.""" @@ -368,8 +382,15 @@ def _setup_agent(self) -> None: def _get_host_deployment_runner(build_dir: Path) -> BaseDeploymentRunner: """Return depoyment runner according to running env.""" deployment_runner: BaseDeploymentRunner + if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"): - deployment_runner = PyInstallerHostDeploymentRunner(build_dir) + # pyinstaller inside! + if platform.system() == "Darwin": + deployment_runner = PyInstallerHostDeploymentRunner(build_dir) + elif platform.system() == "Windows": + deployment_runner = PyInstallerHostDeploymentRunnerWindows(build_dir) + else: + raise ValueError(f"Platform not supported {platform.system()}") else: deployment_runner = HostPythonHostDeploymentRunner(build_dir) return deployment_runner diff --git a/operate/services/health_checker.py b/operate/services/health_checker.py index e1979be13..7a9c27373 100644 --- a/operate/services/health_checker.py +++ b/operate/services/health_checker.py @@ -34,19 +34,28 @@ class HealthChecker: """Health checker manager.""" - SLEEP_PERIOD = 30 - PORT_UP_TIMEOUT = 120 # seconds + SLEEP_PERIOD_DEFAULT = 30 + PORT_UP_TIMEOUT_DEFAULT = 120 # seconds + NUMBER_OF_FAILS_DEFAULT = 5 - def __init__(self, service_manager: ServiceManager) -> None: + def __init__( + self, + service_manager: ServiceManager, + port_up_timeout: int | None = None, + sleep_period: int | None = None, + number_of_fails: int | None = None, + ) -> None: """Init the healtch checker.""" self._jobs: t.Dict[str, asyncio.Task] = {} self.logger = setup_logger(name="operate.health_checker") - self.logger.info("[HEALTCHECKER]: created") self._service_manager = service_manager + self.port_up_timeout = port_up_timeout or self.PORT_UP_TIMEOUT_DEFAULT + self.sleep_period = sleep_period or self.SLEEP_PERIOD_DEFAULT + self.number_of_fails = number_of_fails or self.NUMBER_OF_FAILS_DEFAULT def start_for_service(self, service: str) -> None: """Start for a specific service.""" - self.logger.info(f"[HEALTCHECKER]: Starting healthcheck job for {service}") + self.logger.info(f"[HEALTH_CHECKER]: Starting healthcheck job for {service}") if service in self._jobs: self.stop_for_service(service=service) @@ -62,12 +71,12 @@ def stop_for_service(self, service: str) -> None: if service not in self._jobs: return self.logger.info( - f"[HEALTCHECKER]: Cancelling existing healthcheck_jobs job for {service}" + f"[HEALTH_CHECKER]: Cancelling existing healthcheck_jobs job for {service}" ) status = self._jobs[service].cancel() if not status: self.logger.info( - f"[HEALTCHECKER]: Healthcheck job cancellation for {service} failed" + f"[HEALTH_CHECKER]: Healthcheck job cancellation for {service} failed" ) @staticmethod @@ -90,22 +99,24 @@ async def healthcheck_job( try: self.logger.info( - f"[HEALTCHECKER] Start healthcheck job for service: {service}" + f"[HEALTH_CHECKER] Start healthcheck job for service: {service}" ) async def _wait_for_port(sleep_period: int = 15) -> None: - self.logger.info("[HEALTCHECKER]: wait port is up") + self.logger.info("[HEALTH_CHECKER]: wait port is up") while True: try: await self.check_service_health(service) - self.logger.info("[HEALTCHECKER]: port is UP") + self.logger.info("[HEALTH_CHECKER]: port is UP") return except aiohttp.ClientConnectionError: - self.logger.error("[HEALTCHECKER]: error connecting http port") + self.logger.error( + "[HEALTH_CHECKER]: error connecting http port" + ) await asyncio.sleep(sleep_period) async def _check_port_ready( - timeout: int = self.PORT_UP_TIMEOUT, sleep_period: int = 15 + timeout: int = self.port_up_timeout, sleep_period: int = 15 ) -> bool: try: await asyncio.wait_for( @@ -116,7 +127,7 @@ async def _check_port_ready( return False async def _check_health( - number_of_fails: int = 5, sleep_period: int = self.SLEEP_PERIOD + number_of_fails: int = 5, sleep_period: int = self.sleep_period ) -> None: fails = 0 while True: @@ -125,24 +136,24 @@ async def _check_health( healthy = await self.check_service_health(service) except aiohttp.ClientConnectionError: self.logger.info( - f"[HEALTCHECKER] {service} port read failed. restart" + f"[HEALTH_CHECKER] {service} port read failed. restart" ) return if not healthy: fails += 1 self.logger.info( - f"[HEALTCHECKER] {service} not healthy for {fails} time in a row" + f"[HEALTH_CHECKER] {service} not healthy for {fails} time in a row" ) else: - self.logger.info(f"[HEALTCHECKER] {service} is HEALTHY") + self.logger.info(f"[HEALTH_CHECKER] {service} is HEALTHY") # reset fails if comes healty fails = 0 if fails >= number_of_fails: # too much fails, exit self.logger.error( - f"[HEALTCHECKER] {service} failed {fails} times in a row. restart" + f"[HEALTH_CHECKER] {service} failed {fails} times in a row. restart" ) return await asyncio.sleep(sleep_period) @@ -162,17 +173,20 @@ def _do_restart() -> None: # upper cycle while True: - self.logger.info(f"[HEALTCHECKER] {service} wait for port ready") - if await _check_port_ready(timeout=self.PORT_UP_TIMEOUT): + self.logger.info(f"[HEALTH_CHECKER] {service} wait for port ready") + if await _check_port_ready(timeout=self.port_up_timeout): # blocking till restart needed self.logger.info( - f"[HEALTCHECKER] {service} port is ready, checking health every {self.SLEEP_PERIOD}" + f"[HEALTH_CHECKER] {service} port is ready, checking health every {self.sleep_period}" + ) + await _check_health( + number_of_fails=self.number_of_fails, + sleep_period=self.sleep_period, ) - await _check_health(sleep_period=self.SLEEP_PERIOD) else: self.logger.info( - "[HEALTCHECKER] port not ready within timeout. restart deployment" + "[HEALTH_CHECKER] port not ready within timeout. restart deployment" ) # perform restart diff --git a/operate/services/manage.py b/operate/services/manage.py index 6acf0b462..076701949 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -23,6 +23,7 @@ import logging import os import shutil +import time import traceback import typing as t from collections import Counter @@ -115,21 +116,26 @@ def json(self) -> t.List[t.Dict]: self.logger.warning( f"Failed to load service: {path.name}. Exception: {e}" ) - # delete the invalid path - shutil.rmtree(path) - self.logger.info(f"Deleted invalid service: {path.name}") + # rename the invalid path + timestamp = int(time.time()) + invalid_path = path.parent / f"invalid_{timestamp}_{path.name}" + os.rename(path, invalid_path) + self.logger.info( + f"Renamed invalid service: {path.name} to {invalid_path.name}" + ) + return data def exists(self, service: str) -> bool: """Check if service exists.""" return (self.path / service).exists() - def get_on_chain_manager(self, service: Service) -> OnChainManager: + def get_on_chain_manager(self, ledger_config: LedgerConfig) -> OnChainManager: """Get OnChainManager instance.""" return OnChainManager( - rpc=service.ledger_config.rpc, - wallet=self.wallet_manager.load(service.ledger_config.type), - contracts=CONTRACTS[service.ledger_config.chain], + rpc=ledger_config.rpc, + wallet=self.wallet_manager.load(ledger_config.type), + contracts=CONTRACTS[ledger_config.chain], ) def get_eth_safe_tx_builder(self, ledger_config: LedgerConfig) -> EthSafeTxBuilder: @@ -159,7 +165,9 @@ def load_or_create( service = Service.load(path=path) if service_template is not None: - service.update_user_params_from_template(service_template=service_template) + service.update_user_params_from_template( + service_template=service_template + ) return service @@ -184,22 +192,21 @@ def load_or_create( return service - def _get_on_chain_state(self, chain_config: ChainConfig) -> OnChainState: + def _get_on_chain_state(self, service: Service, chain_id: str) -> OnChainState: + chain_config = service.chain_configs[chain_id] chain_data = chain_config.chain_data ledger_config = chain_config.ledger_config if chain_data.token == NON_EXISTENT_TOKEN: service_state = OnChainState.NON_EXISTENT chain_data.on_chain_state = service_state - # TODO save service state - # service.store() + service.store() return service_state sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) info = sftxb.info(token_id=chain_data.token) service_state = OnChainState(info["service_state"]) chain_data.on_chain_state = service_state - # TODO save service state - # service.store() + service.store() return service_state def _get_on_chain_hash(self, chain_config: ChainConfig) -> t.Optional[str]: @@ -218,10 +225,28 @@ def _get_on_chain_hash(self, chain_config: ChainConfig) -> t.Optional[str]: f"Something went wrong while trying to get the code uri from IPFS: {res}" ) - def deploy_service_onchain( # pylint: disable=too-many-statements + def deploy_service_onchain( # pylint: disable=too-many-statements,too-many-locals self, hash: str, - update: bool = False, + ) -> None: + """ + Deploy as service on-chain + + :param hash: Service hash + """ + # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. + + service = self.load_or_create(hash=hash) + for chain_id in service.chain_configs.keys(): + self._deploy_service_onchain( + hash=hash, + chain_id=chain_id, + ) + + def _deploy_service_onchain( # pylint: disable=too-many-statements,too-many-locals + self, + hash: str, + chain_id: str, ) -> None: """ Deploy as service on-chain @@ -229,49 +254,73 @@ def deploy_service_onchain( # pylint: disable=too-many-statements :param hash: Service hash :param update: Update the existing deployment """ - self.logger.info("Loading service") + # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. + + self.logger.info(f"_deploy_service_onchain_from_safe {chain_id=}") service = self.load_or_create(hash=hash) - user_params = service.chain_data.user_params + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config + chain_data = chain_config.chain_data + user_params = chain_config.chain_data.user_params keys = service.keys instances = [key.address for key in keys] - ocm = self.get_on_chain_manager(service=service) - if user_params.use_staking and not ocm.staking_slots_available( - staking_contract=STAKING[service.ledger_config.chain] - ): - raise ValueError("No staking slots available") + ocm = self.get_on_chain_manager(ledger_config=ledger_config) - if user_params.use_staking and not ocm.staking_rewards_available( - staking_contract=STAKING[service.ledger_config.chain] - ): - raise ValueError("No staking rewards available") + # TODO fix this + os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc + os.environ[ + "OPEN_AUTONOMY_SUBGRAPH_URL" + ] = "https://subgraph.autonolas.tech/subgraphs/name/autonolas-staging" - if service.chain_data.token > -1: + current_agent_id = None + if chain_data.token > -1: self.logger.info("Syncing service state") - info = ocm.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) - service.chain_data.instances = info["instances"] - service.chain_data.multisig = info["multisig"] + info = ocm.info(token_id=chain_data.token) + chain_data.on_chain_state = OnChainState(info["service_state"]) + chain_data.instances = info["instances"] + chain_data.multisig = info["multisig"] service.store() - self.logger.info(f"Service state: {service.chain_data.on_chain_state.name}") + self.logger.info(f"Service state: {chain_data.on_chain_state.name}") + + if user_params.use_staking: + staking_params = ocm.get_staking_params( + staking_contract=STAKING[ledger_config.chain][ + user_params.staking_program_id + ], + ) + else: # TODO fix this - using pearl beta params + staking_params = dict( # nosec + agent_ids=[25], + service_registry="0x9338b5153AE39BB89f50468E608eD9d764B755fD", # nosec + staking_token="0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f", # nosec + service_registry_token_utility="0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8", # nosec + min_staking_deposit=20000000000000000000, + activity_checker="0x155547857680A6D51bebC5603397488988DEb1c8", # nosec + ) if user_params.use_staking: self.logger.info("Checking staking compatibility") - if service.chain_data.on_chain_state in ( + + # TODO: Missing check when the service is currently staked in a program, but needs to be staked + # in a different target program. The In this case, balance = currently staked balance + safe balance + + if chain_data.on_chain_state in ( OnChainState.NON_EXISTENT, OnChainState.PRE_REGISTRATION, ): required_olas = ( - user_params.olas_cost_of_bond + user_params.olas_required_to_stake + staking_params["min_staking_deposit"] + + staking_params["min_staking_deposit"] # bond = staking ) - elif service.chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: - required_olas = user_params.olas_required_to_stake + elif chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: + required_olas = staking_params["min_staking_deposit"] else: required_olas = 0 balance = ( registry_contracts.erc20.get_instance( ledger_api=ocm.ledger_api, - contract_address=OLAS[service.ledger_config.chain], + contract_address=OLAS[ledger_config.chain], ) .functions.balanceOf(ocm.crypto.address) .call() @@ -282,91 +331,108 @@ def deploy_service_onchain( # pylint: disable=too-many-statements f"required olas: {required_olas}; your balance {balance}" ) - if service.chain_data.on_chain_state == OnChainState.NON_EXISTENT: + on_chain_hash = self._get_on_chain_hash(chain_config=chain_config) + current_agent_bond = staking_params[ + "min_staking_deposit" + ] # TODO fixme, read from service registry token utility contract + is_first_mint = ( + self._get_on_chain_state(service=service, chain_id=chain_id) + == OnChainState.NON_EXISTENT + ) + is_update = ( + (not is_first_mint) + and (on_chain_hash is not None) + and ( + on_chain_hash != service.hash + or current_agent_id != staking_params["agent_ids"][0] + or current_agent_bond != staking_params["min_staking_deposit"] + ) + ) + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, ocm # type: ignore # FIXME + ) + + self.logger.info(f"{current_staking_program=}") + self.logger.info(f"{user_params.staking_program_id=}") + self.logger.info(f"{on_chain_hash=}") + self.logger.info(f"{service.hash=}") + self.logger.info(f"{current_agent_id=}") + self.logger.info(f"{staking_params['agent_ids'][0]=}") + self.logger.info(f"{is_first_mint=}") + self.logger.info(f"{is_update=}") + + if chain_data.on_chain_state == OnChainState.NON_EXISTENT: self.logger.info("Minting service") - service.chain_data.token = t.cast( + chain_data.token = t.cast( int, ocm.mint( package_path=service.service_path, - agent_id=user_params.agent_id, + agent_id=staking_params["agent_ids"][0], number_of_slots=service.helper.config.number_of_agents, cost_of_bond=( - user_params.olas_cost_of_bond + staking_params["min_staking_deposit"] if user_params.use_staking else user_params.cost_of_bond ), threshold=user_params.threshold, nft=IPFSHash(user_params.nft), - update_token=service.chain_data.token if update else None, + update_token=chain_data.token if is_update else None, token=( - OLAS[service.ledger_config.chain] - if user_params.use_staking - else None + OLAS[ledger_config.chain] if user_params.use_staking else None ), ).get("token"), ) - service.chain_data.on_chain_state = OnChainState.PRE_REGISTRATION + chain_data.on_chain_state = OnChainState.PRE_REGISTRATION service.store() - info = ocm.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) + info = ocm.info(token_id=chain_data.token) + chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state == OnChainState.PRE_REGISTRATION: + if chain_data.on_chain_state == OnChainState.PRE_REGISTRATION: self.logger.info("Activating service") ocm.activate( - service_id=service.chain_data.token, - token=( - OLAS[service.ledger_config.chain] - if user_params.use_staking - else None - ), + service_id=chain_data.token, + token=(OLAS[ledger_config.chain] if user_params.use_staking else None), ) - service.chain_data.on_chain_state = OnChainState.ACTIVE_REGISTRATION + chain_data.on_chain_state = OnChainState.ACTIVE_REGISTRATION service.store() - info = ocm.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) + info = ocm.info(token_id=chain_data.token) + chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: + if chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: self.logger.info("Registering agent instances") + agent_id = staking_params["agent_ids"][0] ocm.register( - service_id=service.chain_data.token, + service_id=chain_data.token, instances=instances, - agents=[user_params.agent_id for _ in instances], - token=( - OLAS[service.ledger_config.chain] - if user_params.use_staking - else None - ), + agents=[agent_id for _ in instances], + token=(OLAS[ledger_config.chain] if user_params.use_staking else None), ) - service.chain_data.on_chain_state = OnChainState.FINISHED_REGISTRATION + chain_data.on_chain_state = OnChainState.FINISHED_REGISTRATION service.store() - info = ocm.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) + info = ocm.info(token_id=chain_data.token) + chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state == OnChainState.FINISHED_REGISTRATION: + if chain_data.on_chain_state == OnChainState.FINISHED_REGISTRATION: self.logger.info("Deploying service") ocm.deploy( - service_id=service.chain_data.token, - reuse_multisig=update, - token=( - OLAS[service.ledger_config.chain] - if user_params.use_staking - else None - ), + service_id=chain_data.token, + reuse_multisig=is_update, + token=(OLAS[ledger_config.chain] if user_params.use_staking else None), ) - service.chain_data.on_chain_state = OnChainState.DEPLOYED + chain_data.on_chain_state = OnChainState.DEPLOYED service.store() - info = ocm.info(token_id=service.chain_data.token) - service.chain_data = OnChainData( - token=service.chain_data.token, + info = ocm.info(token_id=chain_data.token) + chain_data = OnChainData( + token=chain_data.token, instances=info["instances"], multisig=info["multisig"], staked=False, - on_chain_state=service.chain_data.on_chain_state, - user_params=service.chain_data.user_params, + on_chain_state=chain_data.on_chain_state, + user_params=chain_data.user_params, ) service.store() @@ -410,7 +476,9 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to # TODO fix this os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc - os.environ["OPEN_AUTONOMY_SUBGRAPH_URL"] = "https://subgraph.autonolas.tech/subgraphs/name/autonolas-staging" + os.environ[ + "OPEN_AUTONOMY_SUBGRAPH_URL" + ] = "https://subgraph.autonolas.tech/subgraphs/name/autonolas-staging" current_agent_id = None if chain_data.token > -1: @@ -425,16 +493,18 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to if user_params.use_staking: staking_params = sftxb.get_staking_params( - staking_contract=STAKING[ledger_config.chain][user_params.staking_program_id], + staking_contract=STAKING[ledger_config.chain][ + user_params.staking_program_id + ], ) else: # TODO fix this - using pearl beta params - staking_params = dict( + staking_params = dict( # nosec agent_ids=[25], service_registry="0x9338b5153AE39BB89f50468E608eD9d764B755fD", # nosec staking_token="0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f", # nosec service_registry_token_utility="0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8", # nosec min_staking_deposit=20000000000000000000, - activity_checker="0x155547857680A6D51bebC5603397488988DEb1c8" # nosec + activity_checker="0x155547857680A6D51bebC5603397488988DEb1c8", # nosec ) if user_params.use_staking: @@ -448,7 +518,8 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to OnChainState.PRE_REGISTRATION, ): required_olas = ( - staking_params["min_staking_deposit"] + staking_params["min_staking_deposit"] # bond = staking + staking_params["min_staking_deposit"] + + staking_params["min_staking_deposit"] # bond = staking ) elif chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: required_olas = staking_params["min_staking_deposit"] @@ -470,13 +541,25 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to ) on_chain_hash = self._get_on_chain_hash(chain_config=chain_config) - is_first_mint = self._get_on_chain_state(chain_config=chain_config) == OnChainState.NON_EXISTENT + current_agent_bond = staking_params[ + "min_staking_deposit" + ] # TODO fixme, read from service registry token utility contract + is_first_mint = ( + self._get_on_chain_state(service=service, chain_id=chain_id) + == OnChainState.NON_EXISTENT + ) is_update = ( (not is_first_mint) and (on_chain_hash is not None) - and (on_chain_hash != service.hash or current_agent_id != staking_params["agent_ids"][0]) + and ( + on_chain_hash != service.hash + or current_agent_id != staking_params["agent_ids"][0] + or current_agent_bond != staking_params["min_staking_deposit"] + ) + ) + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, sftxb ) - current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) self.logger.info(f"{current_staking_program=}") self.logger.info(f"{user_params.staking_program_id=}") @@ -488,13 +571,13 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to self.logger.info(f"{is_update=}") if is_update: - self._terminate_service_on_chain_from_safe( - hash=hash, - chain_id=chain_id - ) + self._terminate_service_on_chain_from_safe(hash=hash, chain_id=chain_id) # Update service - if self._get_on_chain_state(chain_config=chain_config) == OnChainState.PRE_REGISTRATION: + if ( + self._get_on_chain_state(service=service, chain_id=chain_id) + == OnChainState.PRE_REGISTRATION + ): self.logger.info("Updating service") receipt = ( sftxb.new_tx() @@ -533,10 +616,14 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() # Mint service - if self._get_on_chain_state(chain_config=chain_config) == OnChainState.NON_EXISTENT: - + if ( + self._get_on_chain_state(service=service, chain_id=chain_id) + == OnChainState.NON_EXISTENT + ): if user_params.use_staking and not sftxb.staking_slots_available( - staking_contract=STAKING[ledger_config.chain][user_params.staking_program_id] + staking_contract=STAKING[ledger_config.chain][ + user_params.staking_program_id + ] ): raise ValueError("No staking slots available") @@ -578,7 +665,10 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to chain_data.on_chain_state = OnChainState.PRE_REGISTRATION service.store() - if self._get_on_chain_state(chain_config=chain_config) == OnChainState.PRE_REGISTRATION: + if ( + self._get_on_chain_state(service=service, chain_id=chain_id) + == OnChainState.PRE_REGISTRATION + ): cost_of_bond = staking_params["min_staking_deposit"] if user_params.use_staking: token_utility = staking_params["service_registry_token_utility"] @@ -628,7 +718,10 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to chain_data.on_chain_state = OnChainState.ACTIVE_REGISTRATION service.store() - if self._get_on_chain_state(chain_config=chain_config) == OnChainState.ACTIVE_REGISTRATION: + if ( + self._get_on_chain_state(service=service, chain_id=chain_id) + == OnChainState.ACTIVE_REGISTRATION + ): cost_of_bond = user_params.cost_of_bond if user_params.use_staking: token_utility = staking_params["service_registry_token_utility"] @@ -682,7 +775,10 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to chain_data.on_chain_state = OnChainState.FINISHED_REGISTRATION service.store() - if self._get_on_chain_state(chain_config=chain_config) == OnChainState.FINISHED_REGISTRATION: + if ( + self._get_on_chain_state(service=service, chain_id=chain_id) + == OnChainState.FINISHED_REGISTRATION + ): self.logger.info("Deploying service") reuse_multisig = True @@ -695,7 +791,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to messages = sftxb.get_deploy_data_from_safe( service_id=chain_data.token, reuse_multisig=reuse_multisig, - master_safe=sftxb.wallet.safe, + master_safe=sftxb.wallet.safe, # type: ignore # TODO fix mypy ) tx = sftxb.new_tx() for message in messages: @@ -713,34 +809,48 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() self.stake_service_on_chain_from_safe(hash=hash, chain_id=chain_id) - def terminate_service_on_chain(self, hash: str) -> None: + def terminate_service_on_chain( + self, hash: str, chain_id: t.Optional[str] = None + ) -> None: """ Terminate service on-chain :param hash: Service hash """ + # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. + + self.logger.info("terminate_service_on_chain") service = self.load_or_create(hash=hash) - ocm = self.get_on_chain_manager(service=service) - info = ocm.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state != OnChainState.DEPLOYED: + if chain_id is None: + chain_id = service.home_chain_id + + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config + chain_data = chain_config.chain_data + ocm = self.get_on_chain_manager(ledger_config=ledger_config) + info = ocm.info(token_id=chain_data.token) + chain_data.on_chain_state = OnChainState(info["service_state"]) + + if chain_data.on_chain_state != OnChainState.DEPLOYED: self.logger.info("Cannot terminate service") return self.logger.info("Terminating service") ocm.terminate( - service_id=service.chain_data.token, + service_id=chain_data.token, token=( - OLAS[service.ledger_config.chain] - if service.chain_data.user_params.use_staking + OLAS[ledger_config.chain] + if chain_data.user_params.use_staking else None ), ) - service.chain_data.on_chain_state = OnChainState.TERMINATED_BONDED + chain_data.on_chain_state = OnChainState.TERMINATED_BONDED service.store() - def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: + def _terminate_service_on_chain_from_safe( # pylint: disable=too-many-locals + self, hash: str, chain_id: str + ) -> None: """ Terminate service on-chain @@ -763,7 +873,9 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non chain_data.on_chain_state = OnChainState(info["service_state"]) # Determine if the service is staked in a known staking program - current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, sftxb + ) is_staked = current_staking_program is not None can_unstake = False @@ -780,9 +892,11 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non # Unstake the service if applies if is_staked and can_unstake: - self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) + self.unstake_service_on_chain_from_safe( + hash=hash, chain_id=chain_id, staking_program_id=current_staking_program + ) - if self._get_on_chain_state(chain_config) in ( + if self._get_on_chain_state(service=service, chain_id=chain_id) in ( OnChainState.ACTIVE_REGISTRATION, OnChainState.FINISHED_REGISTRATION, OnChainState.DEPLOYED, @@ -794,7 +908,10 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non ) ).settle() - if self._get_on_chain_state(chain_config) == OnChainState.TERMINATED_BONDED: + if ( + self._get_on_chain_state(service=service, chain_id=chain_id) + == OnChainState.TERMINATED_BONDED + ): self.logger.info("Unbonding service") sftxb.new_tx().add( sftxb.get_unbond_data( @@ -808,17 +925,34 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non counter_instances = Counter(s.lower() for s in instances) if counter_current_safe_owners == counter_instances: + self.logger.info("Service funded for safe swap") + self.fund_service( + hash=hash, + rpc=ledger_config.rpc, + agent_topup=chain_data.user_params.fund_requirements.agent, + agent_fund_threshold=chain_data.user_params.fund_requirements.agent, + safe_topup=0, + safe_fund_treshold=0, + ) + self.logger.info("Swapping Safe owners") sftxb.swap( # noqa: E800 service_id=chain_data.token, # noqa: E800 multisig=chain_data.multisig, # TODO this can be read from the registry owner_key=str( - self.keys_manager.get(key=current_safe_owners[0]).private_key # TODO allow multiple owners + self.keys_manager.get( + key=current_safe_owners[0] + ).private_key # TODO allow multiple owners ), # noqa: E800 - new_owner_address=wallet.safe if wallet.safe else wallet.crypto.address # TODO it should always be safe address + new_owner_address=wallet.safe + if wallet.safe + else wallet.crypto.address, # TODO it should always be safe address ) # noqa: E800 - def _get_current_staking_program(self, chain_data, ledger_config, sftxb) -> t.Optional[str]: + @staticmethod + def _get_current_staking_program( + chain_data: OnChainData, ledger_config: LedgerConfig, sftxb: EthSafeTxBuilder + ) -> t.Optional[str]: if chain_data.token == NON_EXISTENT_TOKEN: return None @@ -832,34 +966,45 @@ def _get_current_staking_program(self, chain_data, ledger_config, sftxb) -> t.Op current_staking_program = staking_program return current_staking_program - def unbond_service_on_chain(self, hash: str) -> None: + def unbond_service_on_chain( + self, hash: str, chain_id: t.Optional[str] = None + ) -> None: """ Unbond service on-chain :param hash: Service hash """ + # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. + service = self.load_or_create(hash=hash) - ocm = self.get_on_chain_manager(service=service) - info = ocm.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state != OnChainState.TERMINATED_BONDED: + if chain_id is None: + chain_id = service.home_chain_id + + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config + chain_data = chain_config.chain_data + ocm = self.get_on_chain_manager(ledger_config=ledger_config) + info = ocm.info(token_id=chain_data.token) + chain_data.on_chain_state = OnChainState(info["service_state"]) + + if chain_data.on_chain_state != OnChainState.TERMINATED_BONDED: self.logger.info("Cannot unbond service") return self.logger.info("Unbonding service") ocm.unbond( - service_id=service.chain_data.token, + service_id=chain_data.token, token=( - OLAS[service.ledger_config.chain] - if service.chain_data.user_params.use_staking + OLAS[ledger_config.chain] + if chain_data.user_params.use_staking else None ), ) - service.chain_data.on_chain_state = OnChainState.UNBONDED + chain_data.on_chain_state = OnChainState.UNBONDED service.store() - def stake_service_on_chain(self, hash: str, chain_id: int, staking_program_id: str) -> None: + def stake_service_on_chain(self, hash: str) -> None: """ Stake service on-chain @@ -867,7 +1012,9 @@ def stake_service_on_chain(self, hash: str, chain_id: int, staking_program_id: s """ raise NotImplementedError - def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: + def stake_service_on_chain_from_safe( # pylint: disable=too-many-statements,too-many-locals + self, hash: str, chain_id: str + ) -> None: """ Stake service on-chain @@ -888,40 +1035,76 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc # Determine if the service is staked in a known staking program - current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, sftxb + ) is_staked = current_staking_program is not None - current_staking_contract = STAKING[ledger_config.chain][current_staking_program] if is_staked else None + current_staking_contract = ( + STAKING[ledger_config.chain][current_staking_program] + if current_staking_program is not None + else None + ) # perform the unstaking flow if necessary if is_staked: - can_unstake = sftxb.can_unstake(chain_config.chain_data.token, current_staking_contract) + can_unstake = sftxb.can_unstake( + chain_config.chain_data.token, current_staking_contract # type: ignore # TODO fix mypy + ) if not chain_config.chain_data.user_params.use_staking and can_unstake: - self.logger.info(f"Use staking is set to false, but service {chain_config.chain_data.token} is staked and can be unstaked. Unstaking...") - self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) + self.logger.info( + f"Use staking is set to false, but service {chain_config.chain_data.token} is staked and can be unstaked. Unstaking..." + ) + self.unstake_service_on_chain_from_safe( + hash=hash, + chain_id=chain_id, + staking_program_id=current_staking_program, + ) info = sftxb.info(token_id=chain_config.chain_data.token) chain_config.chain_data.on_chain_state = OnChainState(info["service_state"]) staking_state = sftxb.staking_status( service_id=chain_data.token, - staking_contract=current_staking_contract, + staking_contract=current_staking_contract, # type: ignore # TODO fix mypy ) if staking_state == StakingState.EVICTED and can_unstake: - self.logger.info(f"Service {chain_config.chain_data.token} has been evicted and can be unstaked. Unstaking...") - self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) + self.logger.info( + f"Service {chain_config.chain_data.token} has been evicted and can be unstaked. Unstaking..." + ) + self.unstake_service_on_chain_from_safe( + hash=hash, + chain_id=chain_id, + staking_program_id=current_staking_program, + ) - if staking_state == StakingState.STAKED and can_unstake and not sftxb.staking_rewards_available(current_staking_contract): + if ( + staking_state == StakingState.STAKED + and can_unstake + and not sftxb.staking_rewards_available(current_staking_contract) # type: ignore # TODO fix mypy + ): self.logger.info( f"There are no rewards available, service {chain_config.chain_data.token} " f"is already staked and can be unstaked. Unstaking..." ) - self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) + self.unstake_service_on_chain_from_safe( + hash=hash, + chain_id=chain_id, + staking_program_id=current_staking_program, + ) - if staking_state == StakingState.STAKED and current_staking_program != target_staking_contract and can_unstake: + if ( + staking_state == StakingState.STAKED + and current_staking_program != target_staking_contract + and can_unstake + ): self.logger.info( f"{chain_config.chain_data.token} is staked in a different staking program. Unstaking..." ) - self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) + self.unstake_service_on_chain_from_safe( + hash=hash, + chain_id=chain_id, + staking_program_id=current_staking_program, + ) staking_state = sftxb.staking_status( service_id=chain_config.chain_data.token, @@ -929,12 +1112,18 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: ) self.logger.info("Checking conditions to stake.") - staking_rewards_available = sftxb.staking_rewards_available(target_staking_contract) + staking_rewards_available = sftxb.staking_rewards_available( + target_staking_contract + ) staking_slots_available = sftxb.staking_slots_available(target_staking_contract) - on_chain_state = self._get_on_chain_state(chain_config=chain_config) - current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) - - self.logger.info(f"use_staking={chain_config.chain_data.user_params.use_staking}") + on_chain_state = self._get_on_chain_state(service=service, chain_id=chain_id) + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, sftxb + ) + + self.logger.info( + f"use_staking={chain_config.chain_data.user_params.use_staking}" + ) self.logger.info(f"{staking_state=}") self.logger.info(f"{staking_rewards_available=}") self.logger.info(f"{staking_slots_available=}") @@ -943,19 +1132,17 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: self.logger.info(f"{target_staking_program=}") if ( - chain_config.chain_data.user_params.use_staking - and staking_state == StakingState.UNSTAKED - and staking_rewards_available - and staking_slots_available - and on_chain_state == OnChainState.DEPLOYED + chain_config.chain_data.user_params.use_staking + and staking_state == StakingState.UNSTAKED + and staking_rewards_available + and staking_slots_available + and on_chain_state == OnChainState.DEPLOYED ): self.logger.info(f"Approving staking: {chain_config.chain_data.token}") sftxb.new_tx().add( sftxb.get_staking_approval_data( service_id=chain_config.chain_data.token, - service_registry=CONTRACTS[ledger_config.chain][ - "service_registry" - ], + service_registry=CONTRACTS[ledger_config.chain]["service_registry"], staking_contract=target_staking_contract, ) ).settle() @@ -970,44 +1157,57 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: chain_config.chain_data.staked = True service.store() - current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, sftxb + ) self.logger.info(f"{target_staking_program=}") self.logger.info(f"{current_staking_program=}") - def unstake_service_on_chain(self, hash: str) -> None: + def unstake_service_on_chain( + self, hash: str, chain_id: t.Optional[str] = None + ) -> None: """ Unbond service on-chain :param hash: Service hash """ + # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. + service = self.load_or_create(hash=hash) - if not service.chain_data.user_params.use_staking: + + if chain_id is None: + chain_id = service.home_chain_id + + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config + chain_data = chain_config.chain_data + ocm = self.get_on_chain_manager(ledger_config=ledger_config) + if not chain_data.user_params.use_staking: self.logger.info("Cannot unstake service, `use_staking` is set to false") return - ocm = self.get_on_chain_manager(service=service) state = ocm.staking_status( - service_id=service.chain_data.token, - staking_contract=STAKING[service.ledger_config.chain], - ) - self.logger.info( - f"Staking status for service {service.chain_data.token}: {state}" + service_id=chain_data.token, + staking_contract=STAKING[ledger_config.chain], # type: ignore # TODO fix mypy ) + self.logger.info(f"Staking status for service {chain_data.token}: {state}") if state not in {StakingState.STAKED, StakingState.EVICTED}: self.logger.info("Cannot unstake service, it's not staked") - service.chain_data.staked = False + chain_data.staked = False service.store() return - self.logger.info(f"Unstaking service: {service.chain_data.token}") + self.logger.info(f"Unstaking service: {chain_data.token}") ocm.unstake( - service_id=service.chain_data.token, - staking_contract=STAKING[service.ledger_config.chain], + service_id=chain_data.token, + staking_contract=STAKING[ledger_config.chain], # type: ignore # TODO fix mypy ) - service.chain_data.staked = False + chain_data.staked = False service.store() - def unstake_service_on_chain_from_safe(self, hash: str, chain_id: str, staking_program_id: str) -> None: + def unstake_service_on_chain_from_safe( + self, hash: str, chain_id: str, staking_program_id: t.Optional[str] = None + ) -> None: """ Unbond service on-chain @@ -1020,6 +1220,12 @@ def unstake_service_on_chain_from_safe(self, hash: str, chain_id: str, staking_p ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data + if staking_program_id is None: + self.logger.info( + "Cannot unstake service, `staking_program_id` is set to None" + ) + return + if not chain_data.user_params.use_staking: self.logger.info("Cannot unstake service, `use_staking` is set to false") return @@ -1029,9 +1235,7 @@ def unstake_service_on_chain_from_safe(self, hash: str, chain_id: str, staking_p service_id=chain_data.token, staking_contract=STAKING[ledger_config.chain][staking_program_id], ) - self.logger.info( - f"Staking status for service {chain_data.token}: {state}" - ) + self.logger.info(f"Staking status for service {chain_data.token}: {state}") if state not in {StakingState.STAKED, StakingState.EVICTED}: self.logger.info("Cannot unstake service, it's not staked") chain_data.staked = False @@ -1048,7 +1252,7 @@ def unstake_service_on_chain_from_safe(self, hash: str, chain_id: str, staking_p chain_data.staked = False service.store() - def fund_service( # pylint: disable=too-many-arguments + def fund_service( # pylint: disable=too-many-arguments,too-many-locals self, hash: str, rpc: t.Optional[str] = None, @@ -1065,10 +1269,11 @@ def fund_service( # pylint: disable=too-many-arguments ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data wallet = self.wallet_manager.load(ledger_config.type) - ledger_api = wallet.ledger_api(chain_type=ledger_config.chain, rpc=rpc if rpc else ledger_config.rpc) + ledger_api = wallet.ledger_api( + chain_type=ledger_config.chain, rpc=rpc if rpc else ledger_config.rpc + ) agent_fund_threshold = ( - agent_fund_threshold - or chain_data.user_params.fund_requirements.agent + agent_fund_threshold or chain_data.user_params.fund_requirements.agent ) for key in service.keys: @@ -1078,8 +1283,7 @@ def fund_service( # pylint: disable=too-many-arguments if agent_balance < agent_fund_threshold: self.logger.info("Funding agents") to_transfer = ( - agent_topup - or chain_data.user_params.fund_requirements.agent + agent_topup or chain_data.user_params.fund_requirements.agent ) self.logger.info(f"Transferring {to_transfer} units to {key.address}") wallet.transfer( @@ -1097,9 +1301,7 @@ def fund_service( # pylint: disable=too-many-arguments self.logger.info(f"Required balance: {safe_fund_treshold}") if safe_balance < safe_fund_treshold: self.logger.info("Funding safe") - to_transfer = ( - safe_topup or chain_data.user_params.fund_requirements.safe - ) + to_transfer = safe_topup or chain_data.user_params.fund_requirements.safe self.logger.info( f"Transferring {to_transfer} units to {chain_data.multisig}" ) @@ -1177,25 +1379,28 @@ def update_service( """Update a service.""" self.logger.info("-----Entering update local service-----") - old_service = self.load_or_create( - hash=old_hash - ) + old_service = self.load_or_create(hash=old_hash) new_service = self.load_or_create( - hash=new_hash, - service_template=service_template + hash=new_hash, service_template=service_template ) new_service.keys = old_service.keys - # new_Service.home_chain_id = old_service.home_chain_id - # TODO - Ensure this works as expected - New service must copy all chain_data from old service, - # but if service_template is not None, it must copy the user_params - # passed in the service_template and copy the remaining attributes from old_service. + # TODO Ensure this is as intended. + new_service.home_chain_id = old_service.home_chain_id + # new_service must copy all chain_data from old_service. + # Additionally, if service_template is not None, it must overwrite + # the user_params on all chain_data by the values passed through the + # service_template. new_service.chain_configs = {} for chain_id, config in old_service.chain_configs.items(): - new_service.chain_configs[chain_id] = config + new_service.chain_configs[chain_id] = config if service_template: - new_service.chain_configs[chain_id].chain_data.user_params = OnChainUserParams.from_json(service_template["configurations"][chain_id]) + new_service.chain_configs[ + chain_id + ].chain_data.user_params = OnChainUserParams.from_json( + service_template["configurations"][chain_id] # type: ignore # TODO fix mypy + ) new_service.store() diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 120355c94..5b122bb7e 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -242,8 +242,9 @@ def service_info(self, staking_contract: str, service_id: int) -> dict: staking_contract, service_id, ).get("data") - + def agent_ids(self, staking_contract: str) -> t.List[int]: + """Get the agent IDs for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -251,6 +252,7 @@ def agent_ids(self, staking_contract: str) -> t.List[int]: return instance.functions.getAgentIds().call() def service_registry(self, staking_contract: str) -> str: + """Get the service registry address for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -258,6 +260,7 @@ def service_registry(self, staking_contract: str) -> str: return instance.functions.serviceRegistry().call() def staking_token(self, staking_contract: str) -> str: + """Get the staking token address for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -265,6 +268,7 @@ def staking_token(self, staking_contract: str) -> str: return instance.functions.stakingToken().call() def service_registry_token_utility(self, staking_contract: str) -> str: + """Get the service registry token utility address for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -272,6 +276,7 @@ def service_registry_token_utility(self, staking_contract: str) -> str: return instance.functions.serviceRegistryTokenUtility().call() def min_staking_deposit(self, staking_contract: str) -> str: + """Get the minimum staking deposit for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -279,6 +284,7 @@ def min_staking_deposit(self, staking_contract: str) -> str: return instance.functions.minStakingDeposit().call() def activity_checker(self, staking_contract: str) -> str: + """Get the activity checker address for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -529,14 +535,6 @@ def ledger_api(self) -> LedgerApi: ) return ledger_api - def owner_of(self, token_id: int) -> str: - """Get owner of a service.""" - self._patch() - ledger_api, _ = OnChainHelper.get_ledger_and_crypto_objects( - chain_type=self.chain_type - ) - - def info(self, token_id: int) -> t.Dict: """Get service info.""" self._patch() @@ -574,7 +572,6 @@ def info(self, token_id: int) -> t.Dict: instances=instances, ) - def get_service_safe_owners(self, service_id: int) -> t.List[str]: """Get list of owners.""" ledger_api, _ = OnChainHelper.get_ledger_and_crypto_objects( @@ -599,13 +596,8 @@ def get_service_safe_owners(self, service_id: int) -> t.List[str]: contract_address=multisig_address, ).get("owners", []) - def swap( # pylint: disable=too-many-arguments,too-many-locals - self, - service_id: int, - multisig: str, - owner_key: str, - new_owner_address: str + self, service_id: int, multisig: str, owner_key: str, new_owner_address: str ) -> None: """Swap safe owner.""" logging.info(f"Swapping safe for service {service_id} [{multisig}]...") @@ -634,9 +626,7 @@ def swap( # pylint: disable=too-many-arguments,too-many-locals ledger_api=manager.ledger_api, contract_address=multisig, old_owner=manager.ledger_api.api.to_checksum_address(owner_to_swap), - new_owner=manager.ledger_api.api.to_checksum_address( - new_owner_address - ), + new_owner=manager.ledger_api.api.to_checksum_address(new_owner_address), ).get("data") multisend_txs.append( { @@ -720,6 +710,55 @@ def staking_rewards_available(self, staking_contract: str) -> bool: ) return available_rewards > 0 + def staking_status(self, service_id: int, staking_contract: str) -> StakingState: + """Stake the service""" + self._patch() + return StakingManager( + key=self.wallet.key_path, + password=self.wallet.password, + chain_type=self.chain_type, + ).status( + service_id=service_id, + staking_contract=staking_contract, + ) + + def get_staking_params(self, staking_contract: str) -> t.Dict: + """Get agent IDs for the staking contract""" + self._patch() + staking_manager = StakingManager( + key=self.wallet.key_path, + password=self.wallet.password, + chain_type=self.chain_type, + ) + agent_ids = staking_manager.agent_ids( + staking_contract=staking_contract, + ) + service_registry = staking_manager.service_registry( + staking_contract=staking_contract, + ) + staking_token = staking_manager.staking_token( + staking_contract=staking_contract, + ) + service_registry_token_utility = staking_manager.service_registry_token_utility( + staking_contract=staking_contract, + ) + min_staking_deposit = staking_manager.min_staking_deposit( + staking_contract=staking_contract, + ) + activity_checker = staking_manager.activity_checker( + staking_contract=staking_contract, + ) + + return dict( + agent_ids=agent_ids, + service_registry=service_registry, + staking_token=staking_token, + service_registry_token_utility=service_registry_token_utility, + min_staking_deposit=min_staking_deposit, + activity_checker=activity_checker, + ) + + class OnChainManager(_ChainUtil): """On chain service management.""" @@ -974,7 +1013,7 @@ def get_mint_tx_data( # pylint: disable=too-many-arguments ) .load_metadata() .verify_nft(nft=nft) - #.verify_service_dependencies(agent_id=agent_id) # TODO add this check once subgraph production indexes agent 25 + .verify_service_dependencies(agent_id=agent_id) .publish_metadata() ) instance = registry_contracts.service_manager.get_instance( @@ -1003,9 +1042,9 @@ def get_mint_tx_data( # pylint: disable=too-many-arguments [agent_id], [[number_of_slots, cost_of_bond]], threshold, - update_token + update_token, ], - ) + ) return { "to": self.contracts["service_manager"], @@ -1139,7 +1178,11 @@ def get_deploy_data_from_safe( ) approve_hash_message = None if reuse_multisig: - _deployment_payload, approve_hash_message, error = get_reuse_multisig_from_safe_payload( + ( + _deployment_payload, + approve_hash_message, + error, + ) = get_reuse_multisig_from_safe_payload( ledger_api=self.ledger_api, chain_type=self.chain_type, service_id=service_id, @@ -1289,54 +1332,6 @@ def staking_slots_available(self, staking_contract: str) -> bool: staking_contract=staking_contract, ) - def staking_status(self, service_id: int, staking_contract: str) -> StakingState: - """Stake the service""" - self._patch() - return StakingManager( - key=self.wallet.key_path, - password=self.wallet.password, - chain_type=self.chain_type, - ).status( - service_id=service_id, - staking_contract=staking_contract, - ) - - def get_staking_params(self, staking_contract: str) -> t.Dict: - """Get agent IDs for the staking contract""" - self._patch() - staking_manager = StakingManager( - key=self.wallet.key_path, - password=self.wallet.password, - chain_type=self.chain_type, - ) - agent_ids = staking_manager.agent_ids( - staking_contract=staking_contract, - ) - service_registry = staking_manager.service_registry( - staking_contract=staking_contract, - ) - staking_token = staking_manager.staking_token( - staking_contract=staking_contract, - ) - service_registry_token_utility = staking_manager.service_registry_token_utility( - staking_contract=staking_contract, - ) - min_staking_deposit = staking_manager.min_staking_deposit( - staking_contract=staking_contract, - ) - activity_checker = staking_manager.activity_checker( - staking_contract=staking_contract, - ) - - return dict( - agent_ids=agent_ids, - service_registry=service_registry, - staking_token=staking_token, - service_registry_token_utility=service_registry_token_utility, - min_staking_deposit=min_staking_deposit, - activity_checker=activity_checker - ) - def can_unstake(self, service_id: int, staking_contract: str) -> bool: """Can unstake the service?""" try: @@ -1358,26 +1353,25 @@ def get_swap_data(self, service_id: int, multisig: str, owner_key: str) -> t.Dic raise NotImplementedError() - def get_packed_signature_for_approved_hash(owners: t.Tuple[str]) -> bytes: - """Get the packed signatures.""" - sorted_owners = sorted(owners, key=str.lower) - signatures = b'' - for owner in sorted_owners: - # Convert address to bytes and ensure it is 32 bytes long (left-padded with zeros) - r_bytes = to_bytes(hexstr=owner[2:].rjust(64, '0')) + """Get the packed signatures.""" + sorted_owners = sorted(owners, key=str.lower) + signatures = b"" + for owner in sorted_owners: + # Convert address to bytes and ensure it is 32 bytes long (left-padded with zeros) + r_bytes = to_bytes(hexstr=owner[2:].rjust(64, "0")) - # `s` as 32 zero bytes - s_bytes = b'\x00' * 32 + # `s` as 32 zero bytes + s_bytes = b"\x00" * 32 - # `v` as a single byte - v_bytes = to_bytes(1) + # `v` as a single byte + v_bytes = to_bytes(1) - # Concatenate r, s, and v to form the packed signature - packed_signature = r_bytes + s_bytes + v_bytes - signatures += packed_signature + # Concatenate r, s, and v to form the packed signature + packed_signature = r_bytes + s_bytes + v_bytes + signatures += packed_signature - return signatures + return signatures def get_reuse_multisig_from_safe_payload( # pylint: disable=too-many-locals @@ -1477,7 +1471,7 @@ def get_reuse_multisig_from_safe_payload( # pylint: disable=too-many-locals contract_address=multisend_address, txs=txs, ) - signature_bytes = get_packed_signature_for_approved_hash(owners=(master_safe, )) + signature_bytes = get_packed_signature_for_approved_hash(owners=(master_safe,)) safe_tx_hash = registry_contracts.gnosis_safe.get_raw_safe_transaction_hash( ledger_api=ledger_api, @@ -1517,4 +1511,3 @@ def get_reuse_multisig_from_safe_payload( # pylint: disable=too-many-locals ) payload = multisig_address + safe_exec_data[2:] return payload, approve_hash_message, None - diff --git a/operate/services/service.py b/operate/services/service.py index ea6c563ca..ab2d26315 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -21,8 +21,10 @@ import json import os +import platform import shutil import subprocess # nosec +import sys import typing as t from copy import copy, deepcopy from dataclasses import dataclass @@ -82,12 +84,13 @@ ) +# pylint: disable=no-member,redefined-builtin,too-many-instance-attributes + SAFE_CONTRACT_ADDRESS = "safe_contract_address" ALL_PARTICIPANTS = "all_participants" CONSENSUS_THRESHOLD = "consensus_threshold" DELETE_PREFIX = "delete_" - -# pylint: disable=no-member,redefined-builtin,too-many-instance-attributes +SERVICE_CONFIG_VERSION = 2 DUMMY_MULTISIG = "0xm" NON_EXISTENT_TOKEN = -1 @@ -238,7 +241,7 @@ def __init__(self, path: Path) -> None: self.path = path self.config = load_service_config(service_path=path) - def ledger_configs(self) -> "LedgerConfigs": + def ledger_configs(self) -> LedgerConfigs: """Get ledger configs.""" ledger_configs = {} for override in self.config.overrides: @@ -271,11 +274,17 @@ class HostDeploymentGenerator(BaseDeploymentGenerator): def generate_config_tendermint(self) -> "HostDeploymentGenerator": """Generate tendermint configuration.""" tmhome = str(self.build_dir / "node") + tendermint_executable = str( + shutil.which("tendermint"), + ) + # TODO: move all platform related things to a dedicated file + if platform.system() == "Windows": + tendermint_executable = str( + Path(os.path.dirname(sys.executable)) / "tendermint.exe" + ) subprocess.run( # pylint: disable=subprocess-run-check # nosec args=[ - str( - shutil.which("tendermint"), - ), + tendermint_executable, "--home", tmhome, "init", @@ -416,7 +425,10 @@ def _build_docker( builder.deplopyment_type = DockerComposeGenerator.deployment_type builder.try_update_abci_connection_params() - home_chain_data = service.chain_configs[service.home_chain_id] + home_chain_data = service.chain_configs[service.home_chain_id].chain_data + home_chain_ledger_config = service.chain_configs[ + service.home_chain_id + ].ledger_config builder.try_update_runtime_params( multisig_address=home_chain_data.multisig, agent_instances=home_chain_data.instances, @@ -425,8 +437,8 @@ def _build_docker( ) # TODO: Support for multiledger builder.try_update_ledger_params( - chain=LedgerType(service.ledger_config.type).name.lower(), - address=service.ledger_config.rpc, + chain=LedgerType(home_chain_ledger_config.type).name.lower(), + address=home_chain_ledger_config.rpc, ) # build deployment @@ -656,15 +668,19 @@ class Service(LocalResource): @classmethod def migrate_format(cls, path: Path) -> None: """Migrate the JSON file format if needed.""" - file_path = path / Service._file if Service._file is not None and path.name != Service._file else path - - with open(file_path, 'r', encoding='utf-8') as file: + file_path = ( + path / Service._file + if Service._file is not None and path.name != Service._file + else path + ) + + with open(file_path, "r", encoding="utf-8") as file: data = json.load(file) - - if 'version' in data: + + if "version" in data: # Data is already in the new format return - + # Migrate from old format to new format new_data = { "version": 2, @@ -676,30 +692,42 @@ def migrate_format(cls, path: Path) -> None: "ledger_config": { "rpc": data.get("ledger_config", {}).get("rpc"), "type": data.get("ledger_config", {}).get("type"), - "chain": data.get("ledger_config", {}).get("chain") + "chain": data.get("ledger_config", {}).get("chain"), }, "chain_data": { "instances": data.get("chain_data", {}).get("instances", []), "token": data.get("chain_data", {}).get("token"), "multisig": data.get("chain_data", {}).get("multisig"), "staked": data.get("chain_data", {}).get("staked", False), - "on_chain_state": data.get("chain_data", {}).get("on_chain_state", 3), + "on_chain_state": data.get("chain_data", {}).get( + "on_chain_state", 3 + ), "user_params": { "staking_program_id": "pearl_alpha", - "nft": data.get("chain_data", {}).get("user_params", {}).get("nft"), - "threshold": data.get("chain_data", {}).get("user_params", {}).get("threshold"), - "use_staking": data.get("chain_data", {}).get("user_params", {}).get("use_staking"), - "cost_of_bond": data.get("chain_data", {}).get("user_params", {}).get("cost_of_bond"), - "fund_requirements": data.get("chain_data", {}).get("user_params", {}).get("fund_requirements", {}) - } - } + "nft": data.get("chain_data", {}) + .get("user_params", {}) + .get("nft"), + "threshold": data.get("chain_data", {}) + .get("user_params", {}) + .get("threshold"), + "use_staking": data.get("chain_data", {}) + .get("user_params", {}) + .get("use_staking"), + "cost_of_bond": data.get("chain_data", {}) + .get("user_params", {}) + .get("cost_of_bond"), + "fund_requirements": data.get("chain_data", {}) + .get("user_params", {}) + .get("fund_requirements", {}), + }, + }, } }, "service_path": data.get("service_path", ""), - "name": data.get("name", "") + "name": data.get("name", ""), } - - with open(file_path, 'w', encoding='utf-8') as file: + + with open(file_path, "w", encoding="utf-8") as file: json.dump(new_data, file, indent=2) @classmethod @@ -725,7 +753,7 @@ def deployment(self) -> Deployment: return t.cast(Deployment, self._deployment) @staticmethod - def new( + def new( # pylint: disable=too-many-locals hash: str, keys: Keys, service_template: ServiceTemplate, @@ -756,7 +784,7 @@ def new( multisig=DUMMY_MULTISIG, staked=False, on_chain_state=OnChainState.NON_EXISTENT, - user_params=OnChainUserParams.from_json(config), + user_params=OnChainUserParams.from_json(config), # type: ignore ) chain_configs[chain] = ChainConfig( @@ -765,7 +793,7 @@ def new( ) service = Service( - version=2, # TODO implement in appropriate place + version=SERVICE_CONFIG_VERSION, name=service_yaml["author"] + "/" + service_yaml["name"], hash=service_template["hash"], keys=keys, @@ -777,11 +805,16 @@ def new( service.store() return service - def update_user_params_from_template(self, service_template: ServiceTemplate): + def update_user_params_from_template( + self, service_template: ServiceTemplate + ) -> None: """Update user params from template.""" for chain, config in service_template["configurations"].items(): - for chain, config in service_template["configurations"].items(): - self.chain_configs[chain].chain_data.user_params = OnChainUserParams.from_json(config) + self.chain_configs[ + chain + ].chain_data.user_params = OnChainUserParams.from_json( + config # type: ignore + ) self.store() diff --git a/package.json b/package.json index c5afe288e..34d5ff1c1 100644 --- a/package.json +++ b/package.json @@ -58,5 +58,5 @@ "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" }, - "version": "0.1.0-rc115" -} \ No newline at end of file + "version": "0.1.0-rc120" +} diff --git a/poetry.lock b/poetry.lock index fd3b19a72..ad092924b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiohttp" @@ -178,22 +178,22 @@ files = [ [[package]] name = "attrs" -version = "23.2.0" +version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -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-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "backoff" @@ -415,63 +415,78 @@ files = [ [[package]] name = "cffi" -version = "1.16.0" +version = "1.17.0" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"}, + {file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"}, + {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"}, + {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"}, + {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"}, + {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"}, + {file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"}, + {file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"}, + {file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"}, + {file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"}, + {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"}, + {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"}, + {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"}, + {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"}, + {file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"}, + {file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"}, + {file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"}, + {file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"}, + {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"}, + {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"}, + {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"}, + {file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"}, + {file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"}, + {file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"}, + {file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"}, + {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"}, + {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"}, + {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"}, + {file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"}, + {file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"}, + {file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"}, + {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"}, + {file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"}, + {file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"}, + {file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"}, + {file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"}, + {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"}, + {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"}, + {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"}, + {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"}, + {file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"}, + {file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"}, + {file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"}, ] [package.dependencies] @@ -694,63 +709,83 @@ requests = "*" [[package]] name = "coverage" -version = "7.6.0" +version = "7.6.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd"}, - {file = "coverage-7.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c"}, - {file = "coverage-7.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463"}, - {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791"}, - {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c"}, - {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783"}, - {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6"}, - {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb"}, - {file = "coverage-7.6.0-cp310-cp310-win32.whl", hash = "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c"}, - {file = "coverage-7.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169"}, - {file = "coverage-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933"}, - {file = "coverage-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d"}, - {file = "coverage-7.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94"}, - {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1"}, - {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac"}, - {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57"}, - {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d"}, - {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63"}, - {file = "coverage-7.6.0-cp311-cp311-win32.whl", hash = "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713"}, - {file = "coverage-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1"}, - {file = "coverage-7.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"}, - {file = "coverage-7.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8"}, - {file = "coverage-7.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5"}, - {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807"}, - {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382"}, - {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b"}, - {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee"}, - {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605"}, - {file = "coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da"}, - {file = "coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67"}, - {file = "coverage-7.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b"}, - {file = "coverage-7.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d"}, - {file = "coverage-7.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca"}, - {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b"}, - {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44"}, - {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03"}, - {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6"}, - {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b"}, - {file = "coverage-7.6.0-cp38-cp38-win32.whl", hash = "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428"}, - {file = "coverage-7.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8"}, - {file = "coverage-7.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c"}, - {file = "coverage-7.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2"}, - {file = "coverage-7.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390"}, - {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b"}, - {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450"}, - {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6"}, - {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166"}, - {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd"}, - {file = "coverage-7.6.0-cp39-cp39-win32.whl", hash = "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2"}, - {file = "coverage-7.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca"}, - {file = "coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6"}, - {file = "coverage-7.6.0.tar.gz", hash = "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, ] [package.extras] @@ -1347,13 +1382,13 @@ files = [ [[package]] name = "googleapis-common-protos" -version = "1.63.2" +version = "1.65.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87"}, - {file = "googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945"}, + {file = "googleapis_common_protos-1.65.0-py2.py3-none-any.whl", hash = "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63"}, + {file = "googleapis_common_protos-1.65.0.tar.gz", hash = "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0"}, ] [package.dependencies] @@ -1403,61 +1438,61 @@ files = [ [[package]] name = "grpcio" -version = "1.65.1" +version = "1.66.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" files = [ - {file = "grpcio-1.65.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:3dc5f928815b8972fb83b78d8db5039559f39e004ec93ebac316403fe031a062"}, - {file = "grpcio-1.65.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:8333ca46053c35484c9f2f7e8d8ec98c1383a8675a449163cea31a2076d93de8"}, - {file = "grpcio-1.65.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:7af64838b6e615fff0ec711960ed9b6ee83086edfa8c32670eafb736f169d719"}, - {file = "grpcio-1.65.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbb64b4166362d9326f7efbf75b1c72106c1aa87f13a8c8b56a1224fac152f5c"}, - {file = "grpcio-1.65.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8422dc13ad93ec8caa2612b5032a2b9cd6421c13ed87f54db4a3a2c93afaf77"}, - {file = "grpcio-1.65.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4effc0562b6c65d4add6a873ca132e46ba5e5a46f07c93502c37a9ae7f043857"}, - {file = "grpcio-1.65.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a6c71575a2fedf259724981fd73a18906513d2f306169c46262a5bae956e6364"}, - {file = "grpcio-1.65.1-cp310-cp310-win32.whl", hash = "sha256:34966cf526ef0ea616e008d40d989463e3db157abb213b2f20c6ce0ae7928875"}, - {file = "grpcio-1.65.1-cp310-cp310-win_amd64.whl", hash = "sha256:ca931de5dd6d9eb94ff19a2c9434b23923bce6f767179fef04dfa991f282eaad"}, - {file = "grpcio-1.65.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:bbb46330cc643ecf10bd9bd4ca8e7419a14b6b9dedd05f671c90fb2c813c6037"}, - {file = "grpcio-1.65.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d827a6fb9215b961eb73459ad7977edb9e748b23e3407d21c845d1d8ef6597e5"}, - {file = "grpcio-1.65.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:6e71aed8835f8d9fbcb84babc93a9da95955d1685021cceb7089f4f1e717d719"}, - {file = "grpcio-1.65.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a1c84560b3b2d34695c9ba53ab0264e2802721c530678a8f0a227951f453462"}, - {file = "grpcio-1.65.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27adee2338d697e71143ed147fe286c05810965d5d30ec14dd09c22479bfe48a"}, - {file = "grpcio-1.65.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f62652ddcadc75d0e7aa629e96bb61658f85a993e748333715b4ab667192e4e8"}, - {file = "grpcio-1.65.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:71a05fd814700dd9cb7d9a507f2f6a1ef85866733ccaf557eedacec32d65e4c2"}, - {file = "grpcio-1.65.1-cp311-cp311-win32.whl", hash = "sha256:b590f1ad056294dfaeac0b7e1b71d3d5ace638d8dd1f1147ce4bd13458783ba8"}, - {file = "grpcio-1.65.1-cp311-cp311-win_amd64.whl", hash = "sha256:12e9bdf3b5fd48e5fbe5b3da382ad8f97c08b47969f3cca81dd9b36b86ed39e2"}, - {file = "grpcio-1.65.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:54cb822e177374b318b233e54b6856c692c24cdbd5a3ba5335f18a47396bac8f"}, - {file = "grpcio-1.65.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:aaf3c54419a28d45bd1681372029f40e5bfb58e5265e3882eaf21e4a5f81a119"}, - {file = "grpcio-1.65.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:557de35bdfbe8bafea0a003dbd0f4da6d89223ac6c4c7549d78e20f92ead95d9"}, - {file = "grpcio-1.65.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8bfd95ef3b097f0cc86ade54eafefa1c8ed623aa01a26fbbdcd1a3650494dd11"}, - {file = "grpcio-1.65.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e6a8f3d6c41e6b642870afe6cafbaf7b61c57317f9ec66d0efdaf19db992b90"}, - {file = "grpcio-1.65.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1faaf7355ceed07ceaef0b9dcefa4c98daf1dd8840ed75c2de128c3f4a4d859d"}, - {file = "grpcio-1.65.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:60f1f38eed830488ad2a1b11579ef0f345ff16fffdad1d24d9fbc97ba31804ff"}, - {file = "grpcio-1.65.1-cp312-cp312-win32.whl", hash = "sha256:e75acfa52daf5ea0712e8aa82f0003bba964de7ae22c26d208cbd7bc08500177"}, - {file = "grpcio-1.65.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff5a84907e51924973aa05ed8759210d8cdae7ffcf9e44fd17646cf4a902df59"}, - {file = "grpcio-1.65.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:1fbd6331f18c3acd7e09d17fd840c096f56eaf0ef830fbd50af45ae9dc8dfd83"}, - {file = "grpcio-1.65.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:de5b6be29116e094c5ef9d9e4252e7eb143e3d5f6bd6d50a78075553ab4930b0"}, - {file = "grpcio-1.65.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:e4a3cdba62b2d6aeae6027ae65f350de6dc082b72e6215eccf82628e79efe9ba"}, - {file = "grpcio-1.65.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:941c4869aa229d88706b78187d60d66aca77fe5c32518b79e3c3e03fc26109a2"}, - {file = "grpcio-1.65.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f40cebe5edb518d78b8131e87cb83b3ee688984de38a232024b9b44e74ee53d3"}, - {file = "grpcio-1.65.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2ca684ba331fb249d8a1ce88db5394e70dbcd96e58d8c4b7e0d7b141a453dce9"}, - {file = "grpcio-1.65.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8558f0083ddaf5de64a59c790bffd7568e353914c0c551eae2955f54ee4b857f"}, - {file = "grpcio-1.65.1-cp38-cp38-win32.whl", hash = "sha256:8d8143a3e3966f85dce6c5cc45387ec36552174ba5712c5dc6fcc0898fb324c0"}, - {file = "grpcio-1.65.1-cp38-cp38-win_amd64.whl", hash = "sha256:76e81a86424d6ca1ce7c16b15bdd6a964a42b40544bf796a48da241fdaf61153"}, - {file = "grpcio-1.65.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:cb5175f45c980ff418998723ea1b3869cce3766d2ab4e4916fbd3cedbc9d0ed3"}, - {file = "grpcio-1.65.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b12c1aa7b95abe73b3e04e052c8b362655b41c7798da69f1eaf8d186c7d204df"}, - {file = "grpcio-1.65.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:3019fb50128b21a5e018d89569ffaaaa361680e1346c2f261bb84a91082eb3d3"}, - {file = "grpcio-1.65.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ae15275ed98ea267f64ee9ddedf8ecd5306a5b5bb87972a48bfe24af24153e8"}, - {file = "grpcio-1.65.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f096ffb881f37e8d4f958b63c74bfc400c7cebd7a944b027357cd2fb8d91a57"}, - {file = "grpcio-1.65.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2f56b5a68fdcf17a0a1d524bf177218c3c69b3947cb239ea222c6f1867c3ab68"}, - {file = "grpcio-1.65.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:941596d419b9736ab548aa0feb5bbba922f98872668847bf0720b42d1d227b9e"}, - {file = "grpcio-1.65.1-cp39-cp39-win32.whl", hash = "sha256:5fd7337a823b890215f07d429f4f193d24b80d62a5485cf88ee06648591a0c57"}, - {file = "grpcio-1.65.1-cp39-cp39-win_amd64.whl", hash = "sha256:1bceeec568372cbebf554eae1b436b06c2ff24cfaf04afade729fb9035408c6c"}, - {file = "grpcio-1.65.1.tar.gz", hash = "sha256:3c492301988cd720cd145d84e17318d45af342e29ef93141228f9cd73222368b"}, + {file = "grpcio-1.66.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:4877ba180591acdf127afe21ec1c7ff8a5ecf0fe2600f0d3c50e8c4a1cbc6492"}, + {file = "grpcio-1.66.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3750c5a00bd644c75f4507f77a804d0189d97a107eb1481945a0cf3af3e7a5ac"}, + {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:a013c5fbb12bfb5f927444b477a26f1080755a931d5d362e6a9a720ca7dbae60"}, + {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1b24c23d51a1e8790b25514157d43f0a4dce1ac12b3f0b8e9f66a5e2c4c132f"}, + {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7ffb8ea674d68de4cac6f57d2498fef477cef582f1fa849e9f844863af50083"}, + {file = "grpcio-1.66.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:307b1d538140f19ccbd3aed7a93d8f71103c5d525f3c96f8616111614b14bf2a"}, + {file = "grpcio-1.66.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1c17ebcec157cfb8dd445890a03e20caf6209a5bd4ac5b040ae9dbc59eef091d"}, + {file = "grpcio-1.66.1-cp310-cp310-win32.whl", hash = "sha256:ef82d361ed5849d34cf09105d00b94b6728d289d6b9235513cb2fcc79f7c432c"}, + {file = "grpcio-1.66.1-cp310-cp310-win_amd64.whl", hash = "sha256:292a846b92cdcd40ecca46e694997dd6b9be6c4c01a94a0dfb3fcb75d20da858"}, + {file = "grpcio-1.66.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:c30aeceeaff11cd5ddbc348f37c58bcb96da8d5aa93fed78ab329de5f37a0d7a"}, + {file = "grpcio-1.66.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8a1e224ce6f740dbb6b24c58f885422deebd7eb724aff0671a847f8951857c26"}, + {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:a66fe4dc35d2330c185cfbb42959f57ad36f257e0cc4557d11d9f0a3f14311df"}, + {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3ba04659e4fce609de2658fe4dbf7d6ed21987a94460f5f92df7579fd5d0e22"}, + {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4573608e23f7e091acfbe3e84ac2045680b69751d8d67685ffa193a4429fedb1"}, + {file = "grpcio-1.66.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7e06aa1f764ec8265b19d8f00140b8c4b6ca179a6dc67aa9413867c47e1fb04e"}, + {file = "grpcio-1.66.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3885f037eb11f1cacc41f207b705f38a44b69478086f40608959bf5ad85826dd"}, + {file = "grpcio-1.66.1-cp311-cp311-win32.whl", hash = "sha256:97ae7edd3f3f91480e48ede5d3e7d431ad6005bfdbd65c1b56913799ec79e791"}, + {file = "grpcio-1.66.1-cp311-cp311-win_amd64.whl", hash = "sha256:cfd349de4158d797db2bd82d2020554a121674e98fbe6b15328456b3bf2495bb"}, + {file = "grpcio-1.66.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:a92c4f58c01c77205df6ff999faa008540475c39b835277fb8883b11cada127a"}, + {file = "grpcio-1.66.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fdb14bad0835914f325349ed34a51940bc2ad965142eb3090081593c6e347be9"}, + {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:f03a5884c56256e08fd9e262e11b5cfacf1af96e2ce78dc095d2c41ccae2c80d"}, + {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ca2559692d8e7e245d456877a85ee41525f3ed425aa97eb7a70fc9a79df91a0"}, + {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ca1be089fb4446490dd1135828bd42a7c7f8421e74fa581611f7afdf7ab761"}, + {file = "grpcio-1.66.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d639c939ad7c440c7b2819a28d559179a4508783f7e5b991166f8d7a34b52815"}, + {file = "grpcio-1.66.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b9feb4e5ec8dc2d15709f4d5fc367794d69277f5d680baf1910fc9915c633524"}, + {file = "grpcio-1.66.1-cp312-cp312-win32.whl", hash = "sha256:7101db1bd4cd9b880294dec41a93fcdce465bdbb602cd8dc5bd2d6362b618759"}, + {file = "grpcio-1.66.1-cp312-cp312-win_amd64.whl", hash = "sha256:b0aa03d240b5539648d996cc60438f128c7f46050989e35b25f5c18286c86734"}, + {file = "grpcio-1.66.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:ecfe735e7a59e5a98208447293ff8580e9db1e890e232b8b292dc8bd15afc0d2"}, + {file = "grpcio-1.66.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4825a3aa5648010842e1c9d35a082187746aa0cdbf1b7a2a930595a94fb10fce"}, + {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:f517fd7259fe823ef3bd21e508b653d5492e706e9f0ef82c16ce3347a8a5620c"}, + {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1fe60d0772831d96d263b53d83fb9a3d050a94b0e94b6d004a5ad111faa5b5b"}, + {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31a049daa428f928f21090403e5d18ea02670e3d5d172581670be006100db9ef"}, + {file = "grpcio-1.66.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f914386e52cbdeb5d2a7ce3bf1fdfacbe9d818dd81b6099a05b741aaf3848bb"}, + {file = "grpcio-1.66.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bff2096bdba686019fb32d2dde45b95981f0d1490e054400f70fc9a8af34b49d"}, + {file = "grpcio-1.66.1-cp38-cp38-win32.whl", hash = "sha256:aa8ba945c96e73de29d25331b26f3e416e0c0f621e984a3ebdb2d0d0b596a3b3"}, + {file = "grpcio-1.66.1-cp38-cp38-win_amd64.whl", hash = "sha256:161d5c535c2bdf61b95080e7f0f017a1dfcb812bf54093e71e5562b16225b4ce"}, + {file = "grpcio-1.66.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:d0cd7050397b3609ea51727b1811e663ffda8bda39c6a5bb69525ef12414b503"}, + {file = "grpcio-1.66.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0e6c9b42ded5d02b6b1fea3a25f036a2236eeb75d0579bfd43c0018c88bf0a3e"}, + {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:c9f80f9fad93a8cf71c7f161778ba47fd730d13a343a46258065c4deb4b550c0"}, + {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dd67ed9da78e5121efc5c510f0122a972216808d6de70953a740560c572eb44"}, + {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48b0d92d45ce3be2084b92fb5bae2f64c208fea8ceed7fccf6a7b524d3c4942e"}, + {file = "grpcio-1.66.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4d813316d1a752be6f5c4360c49f55b06d4fe212d7df03253dfdae90c8a402bb"}, + {file = "grpcio-1.66.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9c9bebc6627873ec27a70fc800f6083a13c70b23a5564788754b9ee52c5aef6c"}, + {file = "grpcio-1.66.1-cp39-cp39-win32.whl", hash = "sha256:30a1c2cf9390c894c90bbc70147f2372130ad189cffef161f0432d0157973f45"}, + {file = "grpcio-1.66.1-cp39-cp39-win_amd64.whl", hash = "sha256:17663598aadbedc3cacd7bbde432f541c8e07d2496564e22b214b22c7523dac8"}, + {file = "grpcio-1.66.1.tar.gz", hash = "sha256:35334f9c9745add3e357e3372756fd32d925bd52c41da97f4dfdafbde0bf0ee2"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.65.1)"] +protobuf = ["grpcio-tools (>=1.66.1)"] [[package]] name = "h11" @@ -1489,24 +1524,24 @@ test = ["eth-utils (>=1.0.1,<3)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>= [[package]] name = "idna" -version = "3.7" +version = "3.8" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, + {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, ] [[package]] name = "importlib-metadata" -version = "8.2.0" +version = "8.4.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"}, - {file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"}, + {file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, + {file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, ] [package.dependencies] @@ -1936,7 +1971,10 @@ py-multicodec = ">=0.2.0" pymultihash = "0.8.2" pytest = {version = ">=7.0.0,<7.3.0", optional = true, markers = "extra == \"all\""} python-dotenv = ">=0.14.0,<1.0.1" -pyyaml = {version = ">=6.0.1,<7", optional = true, markers = "extra == \"all\""} +pyyaml = [ + {version = ">=6.0.1,<7"}, + {version = ">=6.0.1,<9", optional = true, markers = "extra == \"all\""}, +] requests = ">=2.28.1,<3" semver = ">=2.9.1,<3.0.0" @@ -2076,13 +2114,13 @@ files = [ [[package]] name = "paramiko" -version = "3.4.0" +version = "3.4.1" description = "SSH2 protocol library" optional = false python-versions = ">=3.6" files = [ - {file = "paramiko-3.4.0-py3-none-any.whl", hash = "sha256:43f0b51115a896f9c00f59618023484cb3a14b98bbceab43394a39c6739b7ee7"}, - {file = "paramiko-3.4.0.tar.gz", hash = "sha256:aac08f26a31dc4dffd92821527d1682d99d52f9ef6851968114a8728f3c274d3"}, + {file = "paramiko-3.4.1-py3-none-any.whl", hash = "sha256:8e49fd2f82f84acf7ffd57c64311aa2b30e575370dc23bdb375b10262f7eac32"}, + {file = "paramiko-3.4.1.tar.gz", hash = "sha256:8b15302870af7f6652f2e038975c1d2973f06046cb5d7d65355668b3ecbece0c"}, ] [package.dependencies] @@ -2111,13 +2149,13 @@ regex = ">=2022.3.15" [[package]] name = "pefile" -version = "2023.2.7" +version = "2024.8.26" description = "Python PE parsing module" optional = false python-versions = ">=3.6.0" files = [ - {file = "pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6"}, - {file = "pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc"}, + {file = "pefile-2024.8.26-py3-none-any.whl", hash = "sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f"}, + {file = "pefile-2024.8.26.tar.gz", hash = "sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632"}, ] [[package]] @@ -2418,23 +2456,23 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pyinstaller" -version = "6.9.0" +version = "6.10.0" description = "PyInstaller bundles a Python application and all its dependencies into a single package." optional = false -python-versions = "<3.13,>=3.8" +python-versions = "<3.14,>=3.8" files = [ - {file = "pyinstaller-6.9.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:5ced2e83acf222b936ea94abc5a5cc96588705654b39138af8fb321d9cf2b954"}, - {file = "pyinstaller-6.9.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:f18a3d551834ef8fb7830d48d4cc1527004d0e6b51ded7181e78374ad6111846"}, - {file = "pyinstaller-6.9.0-py3-none-manylinux2014_i686.whl", hash = "sha256:f2fc568de3d6d2a176716a3fc9f20da06d351e8bea5ddd10ecb5659fce3a05b0"}, - {file = "pyinstaller-6.9.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:a0f378f64ad0655d11ade9fde7877e7573fd3d5066231608ce7dfa9040faecdd"}, - {file = "pyinstaller-6.9.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:7bf0c13c5a8560c89540746ae742f4f4b82290e95a6b478374d9f34959fe25d6"}, - {file = "pyinstaller-6.9.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:da994aba14c5686db88796684de265a8665733b4df09b939f7ebdf097d18df72"}, - {file = "pyinstaller-6.9.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:4e3e50743c091a06e6d01c59bdd6d03967b453ee5384a9e790759be4129db4a4"}, - {file = "pyinstaller-6.9.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:b041be2fe78da47a269604d62c940d68c62f9a3913bdf64af4123f7689d47099"}, - {file = "pyinstaller-6.9.0-py3-none-win32.whl", hash = "sha256:2bf4de17a1c63c0b797b38e13bfb4d03b5ee7c0a68e28b915a7eaacf6b76087f"}, - {file = "pyinstaller-6.9.0-py3-none-win_amd64.whl", hash = "sha256:43709c70b1da8441a730327a8ed362bfcfdc3d42c1bf89f3e2b0a163cc4e7d33"}, - {file = "pyinstaller-6.9.0-py3-none-win_arm64.whl", hash = "sha256:f15c1ef11ed5ceb32447dfbdab687017d6adbef7fc32aa359d584369bfe56eda"}, - {file = "pyinstaller-6.9.0.tar.gz", hash = "sha256:f4a75c552facc2e2a370f1e422b971b5e5cdb4058ff38cea0235aa21fc0b378f"}, + {file = "pyinstaller-6.10.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:d60fb22859e11483af735aec115fdde09467cdbb29edd9844839f2c920b748c0"}, + {file = "pyinstaller-6.10.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:46d75359668993ddd98630a3669dc5249f3c446e35239b43bc7f4155bc574748"}, + {file = "pyinstaller-6.10.0-py3-none-manylinux2014_i686.whl", hash = "sha256:3398a98fa17d47ccb31f8779ecbdacec025f7adb2f22757a54b706ac8b4fe906"}, + {file = "pyinstaller-6.10.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e9989f354ae4ed8a3bec7bdb37ae0d170751d6520e500f049c7cd0632d31d5c3"}, + {file = "pyinstaller-6.10.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:b7c90c91921b3749083115b28f30f40abf2bb481ceff196d2b2ce0eaa2b3d429"}, + {file = "pyinstaller-6.10.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6cf876d7d93b8b4f28d1ad57fa24645cf43119c79e985dd5e5f7a801245e6f53"}, + {file = "pyinstaller-6.10.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:db05e3f2f10f9f78c56f1fb163d9cb453433429fe4281218ebaf1ebfd39ba942"}, + {file = "pyinstaller-6.10.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:28eca3817f176fdc19747e1afcf434f13bb9f17a644f611be2c5a61b1f498ed7"}, + {file = "pyinstaller-6.10.0-py3-none-win32.whl", hash = "sha256:703e041718987e46ba0568a2c71ecf2459fddef57cf9edf3efeed4a53e3dae3f"}, + {file = "pyinstaller-6.10.0-py3-none-win_amd64.whl", hash = "sha256:95b55966e563e8b8f31a43882aea10169e9a11fdf38e626d86a2907b640c0701"}, + {file = "pyinstaller-6.10.0-py3-none-win_arm64.whl", hash = "sha256:308e0a8670c9c9ac0cebbf1bbb492e71b6675606f2ec78bc4adfc830d209e087"}, + {file = "pyinstaller-6.10.0.tar.gz", hash = "sha256:143840f8056ff7b910bf8f16f6cd92cc10a6c2680bb76d0a25d558d543d21270"}, ] [package.dependencies] @@ -2443,7 +2481,7 @@ importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""} packaging = ">=22.0" pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""} -pyinstaller-hooks-contrib = ">=2024.7" +pyinstaller-hooks-contrib = ">=2024.8" pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""} setuptools = ">=42.0.0" @@ -2453,13 +2491,13 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"] [[package]] name = "pyinstaller-hooks-contrib" -version = "2024.7" +version = "2024.8" description = "Community maintained hooks for PyInstaller" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pyinstaller_hooks_contrib-2024.7-py2.py3-none-any.whl", hash = "sha256:8bf0775771fbaf96bcd2f4dfd6f7ae6c1dd1b1efe254c7e50477b3c08e7841d8"}, - {file = "pyinstaller_hooks_contrib-2024.7.tar.gz", hash = "sha256:fd5f37dcf99bece184e40642af88be16a9b89613ecb958a8bd1136634fc9fac5"}, + {file = "pyinstaller_hooks_contrib-2024.8-py3-none-any.whl", hash = "sha256:0057fe9a5c398d3f580e73e58793a1d4a8315ca91c3df01efea1c14ed557825a"}, + {file = "pyinstaller_hooks_contrib-2024.8.tar.gz", hash = "sha256:29b68d878ab739e967055b56a93eb9b58e529d5b054fbab7a2f2bacf80cef3e2"}, ] [package.dependencies] @@ -2635,13 +2673,13 @@ files = [ [[package]] name = "pywin32-ctypes" -version = "0.2.2" +version = "0.2.3" description = "A (partial) reimplementation of pywin32 using ctypes/cffi" optional = false python-versions = ">=3.6" files = [ - {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"}, - {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"}, + {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, + {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, ] [[package]] @@ -2861,19 +2899,23 @@ files = [ [[package]] name = "setuptools" -version = "71.1.0" +version = "74.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-71.1.0-py3-none-any.whl", hash = "sha256:33874fdc59b3188304b2e7c80d9029097ea31627180896fb549c578ceb8a0855"}, - {file = "setuptools-71.1.0.tar.gz", hash = "sha256:032d42ee9fb536e33087fb66cac5f840eb9391ed05637b3f2a76a7c8fb477936"}, + {file = "setuptools-74.0.0-py3-none-any.whl", hash = "sha256:0274581a0037b638b9fc1c6883cc71c0210865aaa76073f7882376b641b84e8f"}, + {file = "setuptools-74.0.0.tar.gz", hash = "sha256:a85e96b8be2b906f3e3e789adec6a9323abf79758ecfa3065bd740d81158b11e"}, ] [package.extras] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] [[package]] name = "six" @@ -3112,43 +3154,41 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "watchdog" -version = "4.0.1" +version = "5.0.0" description = "Filesystem events monitoring" optional = false -python-versions = ">=3.8" -files = [ - {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:da2dfdaa8006eb6a71051795856bedd97e5b03e57da96f98e375682c48850645"}, - {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e93f451f2dfa433d97765ca2634628b789b49ba8b504fdde5837cdcf25fdb53b"}, - {file = "watchdog-4.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef0107bbb6a55f5be727cfc2ef945d5676b97bffb8425650dadbb184be9f9a2b"}, - {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:17e32f147d8bf9657e0922c0940bcde863b894cd871dbb694beb6704cfbd2fb5"}, - {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03e70d2df2258fb6cb0e95bbdbe06c16e608af94a3ffbd2b90c3f1e83eb10767"}, - {file = "watchdog-4.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:123587af84260c991dc5f62a6e7ef3d1c57dfddc99faacee508c71d287248459"}, - {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:093b23e6906a8b97051191a4a0c73a77ecc958121d42346274c6af6520dec175"}, - {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:611be3904f9843f0529c35a3ff3fd617449463cb4b73b1633950b3d97fa4bfb7"}, - {file = "watchdog-4.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:62c613ad689ddcb11707f030e722fa929f322ef7e4f18f5335d2b73c61a85c28"}, - {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d4925e4bf7b9bddd1c3de13c9b8a2cdb89a468f640e66fbfabaf735bd85b3e35"}, - {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cad0bbd66cd59fc474b4a4376bc5ac3fc698723510cbb64091c2a793b18654db"}, - {file = "watchdog-4.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a3c2c317a8fb53e5b3d25790553796105501a235343f5d2bf23bb8649c2c8709"}, - {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9904904b6564d4ee8a1ed820db76185a3c96e05560c776c79a6ce5ab71888ba"}, - {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:667f3c579e813fcbad1b784db7a1aaa96524bed53437e119f6a2f5de4db04235"}, - {file = "watchdog-4.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d10a681c9a1d5a77e75c48a3b8e1a9f2ae2928eda463e8d33660437705659682"}, - {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0144c0ea9997b92615af1d94afc0c217e07ce2c14912c7b1a5731776329fcfc7"}, - {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:998d2be6976a0ee3a81fb8e2777900c28641fb5bfbd0c84717d89bca0addcdc5"}, - {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e7921319fe4430b11278d924ef66d4daa469fafb1da679a2e48c935fa27af193"}, - {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f0de0f284248ab40188f23380b03b59126d1479cd59940f2a34f8852db710625"}, - {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bca36be5707e81b9e6ce3208d92d95540d4ca244c006b61511753583c81c70dd"}, - {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ab998f567ebdf6b1da7dc1e5accfaa7c6992244629c0fdaef062f43249bd8dee"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dddba7ca1c807045323b6af4ff80f5ddc4d654c8bce8317dde1bd96b128ed253"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:4513ec234c68b14d4161440e07f995f231be21a09329051e67a2118a7a612d2d"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_i686.whl", hash = "sha256:4107ac5ab936a63952dea2a46a734a23230aa2f6f9db1291bf171dac3ebd53c6"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:6e8c70d2cd745daec2a08734d9f63092b793ad97612470a0ee4cbb8f5f705c57"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f27279d060e2ab24c0aa98363ff906d2386aa6c4dc2f1a374655d4e02a6c5e5e"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:f8affdf3c0f0466e69f5b3917cdd042f89c8c63aebdb9f7c078996f607cdb0f5"}, - {file = "watchdog-4.0.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ac7041b385f04c047fcc2951dc001671dee1b7e0615cde772e84b01fbf68ee84"}, - {file = "watchdog-4.0.1-py3-none-win32.whl", hash = "sha256:206afc3d964f9a233e6ad34618ec60b9837d0582b500b63687e34011e15bb429"}, - {file = "watchdog-4.0.1-py3-none-win_amd64.whl", hash = "sha256:7577b3c43e5909623149f76b099ac49a1a01ca4e167d1785c76eb52fa585745a"}, - {file = "watchdog-4.0.1-py3-none-win_ia64.whl", hash = "sha256:d7b9f5f3299e8dd230880b6c55504a1f69cf1e4316275d1b215ebdd8187ec88d"}, - {file = "watchdog-4.0.1.tar.gz", hash = "sha256:eebaacf674fa25511e8867028d281e602ee6500045b57f43b08778082f7f8b44"}, +python-versions = ">=3.9" +files = [ + {file = "watchdog-5.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bf3216ec994eabb2212df9861f19056ca0d4cd3516d56cb95801933876519bfe"}, + {file = "watchdog-5.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb59ad83a1700304fc1ac7bc53ae9e5cbe9d60a52ed9bba8e2e2d782a201bb2b"}, + {file = "watchdog-5.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1228cb097e855d1798b550be8f0e9f0cfbac4384f9a3e91f66d250d03e11294e"}, + {file = "watchdog-5.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3c177085c3d210d1c73cb4569442bdaef706ebebc423bd7aed9e90fc12b2e553"}, + {file = "watchdog-5.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01ab36cddc836a0f202c66267daaef92ba5c17c7d6436deff0587bb61234c5c9"}, + {file = "watchdog-5.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0834c21efa3e767849b09e667274604c7cdfe30b49eb95d794565c53f4db3c1e"}, + {file = "watchdog-5.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1e26f570dd7f5178656affb24d6f0e22ce66c8daf88d4061a27bfb9ac866b40d"}, + {file = "watchdog-5.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d146331e6b206baa9f6dd40f72b5783ad2302c240df68e7fce196d30588ccf7b"}, + {file = "watchdog-5.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c96b1706430839872a3e33b9370ee3f7a0079f6b828129d88498ad1f96a0f45"}, + {file = "watchdog-5.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:663b096368ed7831ac42259919fdb9e0a1f0a8994d972675dfbcca0225e74de1"}, + {file = "watchdog-5.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:685931412978d00a91a193d9018fc9e394e565e8e7a0c275512a80e59c6e85f8"}, + {file = "watchdog-5.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:109daafc5b0f2a98d1fa9475ff9737eb3559d57b18129a36495e20c71de0b44f"}, + {file = "watchdog-5.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c2b4d90962639ae7cee371ea3a8da506831945d4418eee090c53bc38e6648dc6"}, + {file = "watchdog-5.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e58eafe9cc5ceebe1562cdb89bacdcd0ef470896e8b0139fe677a5abec243da"}, + {file = "watchdog-5.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b8d747bf6d8fe5ce89cb1a36c3724d1599bd4cde3f90fcba518e6260c7058a52"}, + {file = "watchdog-5.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bc16d448a74a929b896ed9578c25756b2125400b19b3258be8d9a681c7ae8e71"}, + {file = "watchdog-5.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7e6b0e9b8a9dc3865d65888b5f5222da4ba9c4e09eab13cff5e305e7b7e7248f"}, + {file = "watchdog-5.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4fe6780915000743074236b21b6c37419aea71112af62237881bc265589fe463"}, + {file = "watchdog-5.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:0710e9502727f688a7e06d48078545c54485b3d6eb53b171810879d8223c362a"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d76efab5248aafbf8a2c2a63cd7b9545e6b346ad1397af8b862a3bb3140787d8"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:ff4e957c45c446de34c513eadce01d0b65da7eee47c01dce472dd136124552c9"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:16c1aa3377bb1f82c5e24277fcbf4e2cac3c4ce46aaaf7212d53caa9076eb7b7"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:22fcad6168fc43cf0e709bd854be5b8edbb0b260f0a6f28f1ea9baa53c6907f7"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:0120b2fa65732797ffa65fa8ee5540c288aa861d91447df298626d6385a24658"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2aa59fab7ff75281778c649557275ca3085eccbdf825a0e2a5ca3810e977afe5"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:78db0fe0336958fc0e1269545c980b6f33d04d184ba191b2800a8b71d3e971a9"}, + {file = "watchdog-5.0.0-py3-none-win32.whl", hash = "sha256:d1acef802916083f2ad7988efc7decf07e46e266916c0a09d8fb9d387288ea12"}, + {file = "watchdog-5.0.0-py3-none-win_amd64.whl", hash = "sha256:3c2d50fdb86aa6df3973313272f5a17eb26eab29ff5a0bf54b6d34597b4dc4e4"}, + {file = "watchdog-5.0.0-py3-none-win_ia64.whl", hash = "sha256:1d17ec7e022c34fa7ddc72aa41bf28c9d1207ffb193df18ba4f6fde453725b3c"}, + {file = "watchdog-5.0.0.tar.gz", hash = "sha256:990aedb9e2f336b45a70aed9c014450e7c4a70fd99c5f5b1834d57e1453a177e"}, ] [package.extras] @@ -3203,83 +3243,97 @@ six = "*" [[package]] name = "websockets" -version = "12.0" +version = "13.0.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false python-versions = ">=3.8" files = [ - {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"}, - {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"}, - {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"}, - {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"}, - {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"}, - {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"}, - {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"}, - {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"}, - {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"}, - {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"}, - {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2"}, - {file = "websockets-12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7"}, - {file = "websockets-12.0-cp38-cp38-win32.whl", hash = "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62"}, - {file = "websockets-12.0-cp38-cp38-win_amd64.whl", hash = "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28"}, - {file = "websockets-12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9"}, - {file = "websockets-12.0-cp39-cp39-win32.whl", hash = "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6"}, - {file = "websockets-12.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8"}, - {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"}, - {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"}, - {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"}, - {file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"}, - {file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"}, - {file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"}, - {file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"}, - {file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"}, + {file = "websockets-13.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1841c9082a3ba4a05ea824cf6d99570a6a2d8849ef0db16e9c826acb28089e8f"}, + {file = "websockets-13.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c5870b4a11b77e4caa3937142b650fbbc0914a3e07a0cf3131f35c0587489c1c"}, + {file = "websockets-13.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f1d3d1f2eb79fe7b0fb02e599b2bf76a7619c79300fc55f0b5e2d382881d4f7f"}, + {file = "websockets-13.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15c7d62ee071fa94a2fc52c2b472fed4af258d43f9030479d9c4a2de885fd543"}, + {file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6724b554b70d6195ba19650fef5759ef11346f946c07dbbe390e039bcaa7cc3d"}, + {file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a952fa2ae57a42ba7951e6b2605e08a24801a4931b5644dfc68939e041bc7f"}, + {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17118647c0ea14796364299e942c330d72acc4b248e07e639d34b75067b3cdd8"}, + {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64a11aae1de4c178fa653b07d90f2fb1a2ed31919a5ea2361a38760192e1858b"}, + {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0617fd0b1d14309c7eab6ba5deae8a7179959861846cbc5cb528a7531c249448"}, + {file = "websockets-13.0.1-cp310-cp310-win32.whl", hash = "sha256:11f9976ecbc530248cf162e359a92f37b7b282de88d1d194f2167b5e7ad80ce3"}, + {file = "websockets-13.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c3c493d0e5141ec055a7d6809a28ac2b88d5b878bb22df8c621ebe79a61123d0"}, + {file = "websockets-13.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:699ba9dd6a926f82a277063603fc8d586b89f4cb128efc353b749b641fcddda7"}, + {file = "websockets-13.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf2fae6d85e5dc384bf846f8243ddaa9197f3a1a70044f59399af001fd1f51d4"}, + {file = "websockets-13.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52aed6ef21a0f1a2a5e310fb5c42d7555e9c5855476bbd7173c3aa3d8a0302f2"}, + {file = "websockets-13.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eb2b9a318542153674c6e377eb8cb9ca0fc011c04475110d3477862f15d29f0"}, + {file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5df891c86fe68b2c38da55b7aea7095beca105933c697d719f3f45f4220a5e0e"}, + {file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac2d146ff30d9dd2fcf917e5d147db037a5c573f0446c564f16f1f94cf87462"}, + {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b8ac5b46fd798bbbf2ac6620e0437c36a202b08e1f827832c4bf050da081b501"}, + {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:46af561eba6f9b0848b2c9d2427086cabadf14e0abdd9fde9d72d447df268418"}, + {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5a06d7f60bc2fc378a333978470dfc4e1415ee52f5f0fce4f7853eb10c1e9df"}, + {file = "websockets-13.0.1-cp311-cp311-win32.whl", hash = "sha256:556e70e4f69be1082e6ef26dcb70efcd08d1850f5d6c5f4f2bcb4e397e68f01f"}, + {file = "websockets-13.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:67494e95d6565bf395476e9d040037ff69c8b3fa356a886b21d8422ad86ae075"}, + {file = "websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a"}, + {file = "websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956"}, + {file = "websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af"}, + {file = "websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf"}, + {file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f52504023b1480d458adf496dc1c9e9811df4ba4752f0bc1f89ae92f4f07d0c"}, + {file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:139add0f98206cb74109faf3611b7783ceafc928529c62b389917a037d4cfdf4"}, + {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab"}, + {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d"}, + {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237"}, + {file = "websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185"}, + {file = "websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99"}, + {file = "websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa"}, + {file = "websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231"}, + {file = "websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9"}, + {file = "websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75"}, + {file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553"}, + {file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920"}, + {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329"}, + {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7"}, + {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2"}, + {file = "websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb"}, + {file = "websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b"}, + {file = "websockets-13.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b74593e9acf18ea5469c3edaa6b27fa7ecf97b30e9dabd5a94c4c940637ab96e"}, + {file = "websockets-13.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:132511bfd42e77d152c919147078460c88a795af16b50e42a0bd14f0ad71ddd2"}, + {file = "websockets-13.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:165bedf13556f985a2aa064309baa01462aa79bf6112fbd068ae38993a0e1f1b"}, + {file = "websockets-13.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e801ca2f448850685417d723ec70298feff3ce4ff687c6f20922c7474b4746ae"}, + {file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30d3a1f041360f029765d8704eae606781e673e8918e6b2c792e0775de51352f"}, + {file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67648f5e50231b5a7f6d83b32f9c525e319f0ddc841be0de64f24928cd75a603"}, + {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4f0426d51c8f0926a4879390f53c7f5a855e42d68df95fff6032c82c888b5f36"}, + {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ef48e4137e8799998a343706531e656fdec6797b80efd029117edacb74b0a10a"}, + {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:249aab278810bee585cd0d4de2f08cfd67eed4fc75bde623be163798ed4db2eb"}, + {file = "websockets-13.0.1-cp38-cp38-win32.whl", hash = "sha256:06c0a667e466fcb56a0886d924b5f29a7f0886199102f0a0e1c60a02a3751cb4"}, + {file = "websockets-13.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1f3cf6d6ec1142412d4535adabc6bd72a63f5f148c43fe559f06298bc21953c9"}, + {file = "websockets-13.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1fa082ea38d5de51dd409434edc27c0dcbd5fed2b09b9be982deb6f0508d25bc"}, + {file = "websockets-13.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a365bcb7be554e6e1f9f3ed64016e67e2fa03d7b027a33e436aecf194febb63"}, + {file = "websockets-13.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10a0dc7242215d794fb1918f69c6bb235f1f627aaf19e77f05336d147fce7c37"}, + {file = "websockets-13.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59197afd478545b1f73367620407b0083303569c5f2d043afe5363676f2697c9"}, + {file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d20516990d8ad557b5abeb48127b8b779b0b7e6771a265fa3e91767596d7d97"}, + {file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1a2e272d067030048e1fe41aa1ec8cfbbaabce733b3d634304fa2b19e5c897f"}, + {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad327ac80ba7ee61da85383ca8822ff808ab5ada0e4a030d66703cc025b021c4"}, + {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:518f90e6dd089d34eaade01101fd8a990921c3ba18ebbe9b0165b46ebff947f0"}, + {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:68264802399aed6fe9652e89761031acc734fc4c653137a5911c2bfa995d6d6d"}, + {file = "websockets-13.0.1-cp39-cp39-win32.whl", hash = "sha256:a5dc0c42ded1557cc7c3f0240b24129aefbad88af4f09346164349391dea8e58"}, + {file = "websockets-13.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b448a0690ef43db5ef31b3a0d9aea79043882b4632cfc3eaab20105edecf6097"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:faef9ec6354fe4f9a2c0bbb52fb1ff852effc897e2a4501e25eb3a47cb0a4f89"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:03d3f9ba172e0a53e37fa4e636b86cc60c3ab2cfee4935e66ed1d7acaa4625ad"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d450f5a7a35662a9b91a64aefa852f0c0308ee256122f5218a42f1d13577d71e"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f55b36d17ac50aa8a171b771e15fbe1561217510c8768af3d546f56c7576cdc"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14b9c006cac63772b31abbcd3e3abb6228233eec966bf062e89e7fa7ae0b7333"}, + {file = "websockets-13.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b79915a1179a91f6c5f04ece1e592e2e8a6bd245a0e45d12fd56b2b59e559a32"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f40de079779acbcdbb6ed4c65af9f018f8b77c5ec4e17a4b737c05c2db554491"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80e4ba642fc87fa532bac07e5ed7e19d56940b6af6a8c61d4429be48718a380f"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a02b0161c43cc9e0232711eff846569fad6ec836a7acab16b3cf97b2344c060"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6aa74a45d4cdc028561a7d6ab3272c8b3018e23723100b12e58be9dfa5a24491"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00fd961943b6c10ee6f0b1130753e50ac5dcd906130dcd77b0003c3ab797d026"}, + {file = "websockets-13.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d93572720d781331fb10d3da9ca1067817d84ad1e7c31466e9f5e59965618096"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:71e6e5a3a3728886caee9ab8752e8113670936a193284be9d6ad2176a137f376"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c4a6343e3b0714e80da0b0893543bf9a5b5fa71b846ae640e56e9abc6fbc4c83"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a678532018e435396e37422a95e3ab87f75028ac79570ad11f5bf23cd2a7d8c"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6716c087e4aa0b9260c4e579bb82e068f84faddb9bfba9906cb87726fa2e870"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e33505534f3f673270dd67f81e73550b11de5b538c56fe04435d63c02c3f26b5"}, + {file = "websockets-13.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acab3539a027a85d568c2573291e864333ec9d912675107d6efceb7e2be5d980"}, + {file = "websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817"}, + {file = "websockets-13.0.1.tar.gz", hash = "sha256:4d6ece65099411cfd9a48d13701d7438d9c34f479046b34c50ff60bb8834e43e"}, ] [[package]] @@ -3401,18 +3455,22 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.19.2" +version = "3.20.1" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, - {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, + {file = "zipp-3.20.1-py3-none-any.whl", hash = "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064"}, + {file = "zipp-3.20.1.tar.gz", hash = "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"}, ] [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] [metadata] lock-version = "2.0" diff --git a/pyproject.toml b/pyproject.toml index 9a58deb5d..a02e08312 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc115" +version = "0.1.0-rc120" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" diff --git a/templates/trader.yaml b/templates/trader.yaml index ed0b8679d..9742c7ba8 100644 --- a/templates/trader.yaml +++ b/templates/trader.yaml @@ -1,6 +1,6 @@ name: "Trader Agent" description: "A single-agent service (sovereign agent) placing bets on Omen" -hash: bafybeicrstlxew36hlxl7pzi73nmd44aibnhwxzkchzlec6t6yhvs7gvhy +hash: bafybeihqtqgohejyebrb4jvd2fgccuasmqk3gc456ylyfa7tcn6rucdrxm image: https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75 service_version: v0.18.1 home_chain_id: 100 diff --git a/tox.ini b/tox.ini index b7de2caf0..88426bd93 100644 --- a/tox.ini +++ b/tox.ini @@ -215,3 +215,6 @@ ignore_missing_imports = True [mypy-psutil.*] ignore_missing_imports = True + +[mypy-eth_utils.*] +ignore_missing_imports = True